3.0.0 update

This commit is contained in:
Jaiden Mispy
2014-12-05 23:33:19 +11:00
parent 9494210945
commit 755e653316
7 changed files with 9598 additions and 130 deletions

View File

@@ -1,4 +1,4 @@
source 'http://rubygems.org' source 'http://rubygems.org'
ruby '1.9.3' ruby '2.1.3'
gem 'twitter_ebooks' gem 'twitter_ebooks'

72
Gemfile.lock Normal file
View File

@@ -0,0 +1,72 @@
GEM
remote: http://rubygems.org/
specs:
addressable (2.3.6)
awesome_print (1.2.0)
bloomfilter-rb (2.1.1)
redis
buftok (0.2.0)
coderay (1.1.0)
engtagger (0.2.0)
equalizer (0.0.9)
eventmachine (1.0.3)
faraday (0.9.0)
multipart-post (>= 1.2, < 3)
fast-stemmer (1.0.2)
gingerice (1.2.2)
addressable
awesome_print
highscore (1.2.0)
bloomfilter-rb (>= 2.1.1)
whatlanguage (>= 1.0.0)
htmlentities (4.3.2)
http (0.6.3)
http_parser.rb (~> 0.6.0)
http_parser.rb (0.6.0)
json (1.8.1)
memoizable (0.4.2)
thread_safe (~> 0.3, >= 0.3.1)
method_source (0.8.2)
multipart-post (2.0.0)
naught (1.0.0)
pry (0.10.1)
coderay (~> 1.1.0)
method_source (~> 0.8.1)
slop (~> 3.4)
redis (3.1.0)
rufus-scheduler (3.0.9)
tzinfo
simple_oauth (0.3.0)
slop (3.6.0)
thread_safe (0.3.4)
twitter (5.13.0)
addressable (~> 2.3)
buftok (~> 0.2.0)
equalizer (~> 0.0.9)
faraday (~> 0.9.0)
http (~> 0.6.0)
http_parser.rb (~> 0.6.0)
json (~> 1.8)
memoizable (~> 0.4.0)
naught (~> 1.0)
simple_oauth (~> 0.3.0)
twitter_ebooks (3.0.0)
engtagger
eventmachine (~> 1.0.3)
fast-stemmer
gingerice
highscore
htmlentities
pry
rufus-scheduler
simple_oauth
twitter (~> 5.0)
tzinfo (1.2.2)
thread_safe (~> 0.1)
whatlanguage (1.0.5)
PLATFORMS
ruby
DEPENDENCIES
twitter_ebooks

View File

@@ -1 +1 @@
worker: ruby run.rb start worker: bundle exec ebooks start

View File

@@ -14,6 +14,6 @@ ebooks consume corpus/username.json
Populate bots.rb with your auth details, the bot username and model name, then: Populate bots.rb with your auth details, the bot username and model name, then:
`./run.rb` `ebooks start`
Also runs as a Heroku app! See the [twitter_ebooks](https://github.com/mispy/twitter_ebooks) README for more information. Also runs as a Heroku app! See the [twitter_ebooks](https://github.com/mispy/twitter_ebooks) README for more information.

194
bots.rb
View File

@@ -1,138 +1,134 @@
#!/usr/bin/env ruby
require 'twitter_ebooks' require 'twitter_ebooks'
include Ebooks
CONSUMER_KEY = "" # Information about a particular Twitter user we know
CONSUMER_SECRET = "" class UserInfo
OATH_TOKEN = "" # oauth token for ebooks account attr_reader :username
OAUTH_TOKEN_SECRET = "" # oauth secret for ebooks account
ROBOT_ID = "ebooks" # Avoid infinite reply chains # @return [Integer] how many times we can pester this user unprompted
TWITTER_USERNAME = "ebooks_username" # Ebooks account username attr_accessor :pesters_left
TEXT_MODEL_NAME = "username" # This should be the name of the text model
DELAY = 2..30 # Simulated human reply delay range in seconds # @param username [String]
BLACKLIST = ['insomnius', 'upulie'] # Grumpy users to avoid interaction with def initialize(username)
SPECIAL_WORDS = ['ebooks', 'bot', 'bots', 'clone', 'singularity', 'world domination'] @username = username
@pesters_left = 1
end
end
# Track who we've randomly interacted with globally class CloneBot < Ebooks::Bot
$have_talked = {} attr_accessor :original, :model_path
class GenBot def configure
def initialize(bot, modelname) # Configuration for all CloneBots
@bot = bot self.consumer_key = ""
@model = nil self.consumer_secret = ""
self.blacklist = ['kylelehk', 'friedrichsays', 'Sudieofna', 'tnietzschequote', 'NerdsOnPeriod', 'FSR', 'BafflingQuotes', 'Obey_Nxme']
bot.consumer_key = CONSUMER_KEY @userinfo = {}
bot.consumer_secret = CONSUMER_SECRET
bot.on_startup do
@model = Model.load("model/#{modelname}.model")
@top100 = @model.keywords.top(100).map(&:to_s).map(&:downcase)
@top50 = @model.keywords.top(20).map(&:to_s).map(&:downcase)
end end
bot.on_message do |dm| def model
bot.delay DELAY do @model_path ||= "model/#{original}.model"
bot.reply dm, @model.make_response(dm[:text]) if @model.nil?
log "Loading model #{model_path}"
@model = Ebooks::Model.load(model_path)
else
@model
end end
end end
bot.on_follow do |user| def top100; @top100 ||= model.keywords.take(100); end
bot.delay DELAY do def top20; @top20 ||= model.keywords.take(20); end
bot.follow user[:screen_name]
def delay(&b)
sleep (1..4).to_a.sample
b.call
end
def on_startup
model
scheduler.cron '0 0 * * *' do
# Each day at midnight, post a single tweet
tweet model.make_statement
end end
end end
bot.on_mention do |tweet, meta| def on_direct_message(dm)
# Avoid infinite reply chains (very small chance of crosstalk) delay do
next if tweet[:user][:screen_name].include?(ROBOT_ID) && rand > 0.05 reply dm, model.make_response(dm.text)
tokens = NLP.tokenize(tweet[:text])
very_interesting = tokens.find_all { |t| @top50.include?(t.downcase) }.length > 2
special = tokens.find { |t| SPECIAL_WORDS.include?(t) }
if very_interesting || special
favorite(tweet)
end
reply(tweet, meta)
end
bot.on_timeline do |tweet, meta|
next if tweet[:retweeted_status] || tweet[:text].start_with?('RT')
next if BLACKLIST.include?(tweet[:user][:screen_name])
tokens = NLP.tokenize(tweet[:text])
# We calculate unprompted interaction probability by how well a
# tweet matches our keywords
interesting = tokens.find { |t| @top100.include?(t.downcase) }
very_interesting = tokens.find_all { |t| @top50.include?(t.downcase) }.length > 2
special = tokens.find { |t| SPECIAL_WORDS.include?(t) }
if special
favorite(tweet)
favd = true # Mark this tweet as favorited
bot.delay DELAY do
bot.follow tweet[:user][:screen_name]
end end
end end
# Any given user will receive at most one random interaction per day def on_mention(tweet)
# (barring special cases) # Become more inclined to pester a user when they talk to us
next if $have_talked[tweet[:user][:screen_name]] userinfo(tweet.user.screen_name).pesters_left += 1
$have_talked[tweet[:user][:screen_name]] = true delay do
reply(tweet, model.make_response(meta(tweet).mentionless, meta(tweet).limit))
end
end
if very_interesting || special def on_timeline(tweet)
favorite(tweet) if (rand < 0.5 && !favd) # Don't fav the tweet if we did earlier return if tweet.retweeted_status?
tokens = Ebooks::NLP.tokenize(tweet.text)
interesting = tokens.find { |t| top100.include?(t.downcase) }
very_interesting = tokens.find_all { |t| top20.include?(t.downcase) }.length > 2
return unless can_pester?(tweet.user.screen_name)
delay do
if very_interesting
favorite(tweet) if rand < 0.5
retweet(tweet) if rand < 0.1 retweet(tweet) if rand < 0.1
reply(tweet, meta) if rand < 0.1 reply(tweet, model.make_response(meta(tweet).mentionless, meta(tweet).limit)) if rand < 0.05
elsif interesting elsif interesting
favorite(tweet) if rand < 0.1 favorite(tweet) if rand < 0.05
reply(tweet, meta) if rand < 0.05 reply(tweet, model.make_response(meta(tweet).mentionless, meta(tweet).limit)) if rand < 0.01
end
end end
end end
# Schedule a main tweet for every day at midnight # Find information we've collected about a user
bot.scheduler.cron '0 0 * * *' do # @param username [String]
bot.tweet @model.make_statement # @return [Ebooks::UserInfo]
$have_talked = {} def userinfo(username)
end @userinfo[username] ||= UserInfo.new(username)
end end
def reply(tweet, meta) # Check if we're allowed to send unprompted tweets to a user
resp = @model.make_response(meta[:mentionless], meta[:limit]) # @param username [String]
@bot.delay DELAY do # @return [Boolean]
@bot.reply tweet, meta[:reply_prefix] + resp def can_pester?(username)
userinfo(username).pesters_left > 0
end end
# Only follow our original user or people who are following our original user
# @param user [Twitter::User]
def can_follow?(username)
@original.nil? || username == @original || twitter.friendship?(username, @original)
end end
def favorite(tweet) def favorite(tweet)
@bot.log "Favoriting @#{tweet[:user][:screen_name]}: #{tweet[:text]}" if !can_follow?(tweet.user.screen_name)
@bot.delay DELAY do log "Unfollowing @#{tweet.user.screen_name}"
@bot.twitter.favorite(tweet[:id]) twitter.unfollow(tweet.user.screen_name)
else
super(tweet)
end end
end end
def retweet(tweet) def on_follow(user)
@bot.log "Retweeting @#{tweet[:user][:screen_name]}: #{tweet[:text]}" if can_follow?(user.screen_name)
@bot.delay DELAY do follow(user.screen_name)
@bot.twitter.retweet(tweet[:id]) else
log "Not following @#{user.screen_name}"
end end
end end
end end
def make_bot(bot, modelname) CloneBot.new("abby_ebooks") do |bot|
GenBot.new(bot, modelname) bot.access_token = ""
end bot.access_token_secret = ""
Ebooks::Bot.new(TWITTER_USERNAME) do |bot| bot.original = "0xabad1dea"
bot.oauth_token = OATH_TOKEN
bot.oauth_token_secret = OAUTH_TOKEN_SECRET
make_bot(bot, TEXT_MODEL_NAME)
end end

9413
model/0xabad1dea.model Normal file

File diff suppressed because it is too large Load Diff

13
run.rb
View File

@@ -1,13 +0,0 @@
#!/usr/bin/env ruby
require_relative 'bots'
if ARGV[0] && ARGV[0] != 'start'
Ebooks::Bot.get(ARGV[0]).start
else
EM.run do
Ebooks::Bot.all.each do |bot|
bot.start
end
end
end