Slightly different pesters model

This commit is contained in:
Jaiden Mispy 2014-11-19 10:07:29 +11:00
parent 24e8ce5ae3
commit 1a40ef85f9
2 changed files with 45 additions and 68 deletions

View file

@ -163,49 +163,9 @@ STR
bot.tweet(statement) bot.tweet(statement)
end end
def self.jsonify(paths) def self.c
usage = <<STR load 'bots.rb'
Usage: ebooks jsonify <old_corpus_path> [old_corpus_path2] [...] require 'pry'; pry
Takes an old-style corpus of plain tweet text and converts it to json.
STR
if paths.empty?
log usage
exit
end
paths.each do |path|
name = File.basename(path).split('.')[0]
new_path = name + ".json"
tweets = []
id = nil
if path.split('.')[-1] == "csv" #from twitter archive
csv_archive = CSV.read(path, :headers=>:first_row)
tweets = csv_archive.map do |tweet|
{ text: tweet['text'], id: tweet['tweet_id'] }
end
else
File.read(path).split("\n").each do |l|
if l.start_with?('# ')
id = l.split('# ')[-1]
else
tweet = { text: l }
if id
tweet[:id] = id
id = nil
end
tweets << tweet
end
end
end
File.open(new_path, 'w') do |f|
log "Writing #{tweets.length} tweets to #{new_path}"
f.write(JSON.pretty_generate(tweets))
end
end
end end
def self.command(args) def self.command(args)
@ -218,7 +178,6 @@ Usage:
ebooks score <model_path> <input> ebooks score <model_path> <input>
ebooks archive <@user> <outpath> ebooks archive <@user> <outpath>
ebooks tweet <model_path> <botname> ebooks tweet <model_path> <botname>
ebooks jsonify <old_corpus_path> [old_corpus_path2] [...]
STR STR
if args.length == 0 if args.length == 0
@ -235,6 +194,7 @@ STR
when "archive" then archive(args[1], args[2]) when "archive" then archive(args[1], args[2])
when "tweet" then tweet(args[1], args[2]) when "tweet" then tweet(args[1], args[2])
when "jsonify" then jsonify(args[1..-1]) when "jsonify" then jsonify(args[1..-1])
when "c" then c
else else
log usage log usage
exit 1 exit 1

View file

@ -10,15 +10,15 @@ module Ebooks
# each user and start dropping them from mentions after two in a row # each user and start dropping them from mentions after two in a row
class UserInfo class UserInfo
attr_reader :username attr_reader :username
attr_accessor :pester_count attr_accessor :pesters_left
def initialize(username) def initialize(username)
@username = username @username = username
@pester_count = 0 @pesters_left = 1
end end
def can_pester? def can_pester?
@pester_count < 2 @pesters_left > 0
end end
end end
@ -35,7 +35,7 @@ module Ebooks
def receive(tweet) def receive(tweet)
@received << tweet @received << tweet
@last_update = Time.now @last_update = Time.now
@userinfo.pester_count = 0 @userinfo.pesters_left += 2
end end
# Make an informed guess as to whether this user is a bot # Make an informed guess as to whether this user is a bot
@ -88,6 +88,9 @@ module Ebooks
@users ||= {} @users ||= {}
@interactions ||= {} @interactions ||= {}
configure(*args, &b) configure(*args, &b)
# Tweet ids we've already observed, to avoid duplication
@seen_tweets ||= {}
end end
def userinfo(username) def userinfo(username)
@ -103,15 +106,17 @@ module Ebooks
end end
end end
def make_client def twitter
@twitter = Twitter::REST::Client.new do |config| @twitter ||= Twitter::REST::Client.new do |config|
config.consumer_key = @consumer_key config.consumer_key = @consumer_key
config.consumer_secret = @consumer_secret config.consumer_secret = @consumer_secret
config.access_token = @access_token config.access_token = @access_token
config.access_token_secret = @access_token_secret config.access_token_secret = @access_token_secret
end end
end
@stream = Twitter::Streaming::Client.new do |config| def stream
@stream ||= Twitter::Streaming::Client.new do |config|
config.consumer_key = @consumer_key config.consumer_key = @consumer_key
config.consumer_secret = @consumer_secret config.consumer_secret = @consumer_secret
config.access_token = @access_token config.access_token = @access_token
@ -183,6 +188,13 @@ module Ebooks
@twitter.block(ev.user.screen_name) @twitter.block(ev.user.screen_name)
end end
# Avoid responding to duplicate tweets
if @seen_tweets[ev.id]
return
else
@seen_tweets[ev.id] = true
end
if meta[:mentions_bot] if meta[:mentions_bot]
log "Mention from @#{ev.user.screen_name}: #{ev.text}" log "Mention from @#{ev.user.screen_name}: #{ev.text}"
interaction(ev.user.screen_name).receive(ev) interaction(ev.user.screen_name).receive(ev)
@ -201,7 +213,8 @@ module Ebooks
def start_stream def start_stream
log "starting tweet stream" log "starting tweet stream"
@stream.user do |ev|
stream.user do |ev|
receive_event ev receive_event ev
end end
end end
@ -212,7 +225,7 @@ module Ebooks
raise ConfigurationError, "bot.username cannot be nil" raise ConfigurationError, "bot.username cannot be nil"
end end
make_client twitter
fire(:startup) fire(:startup)
end end
@ -249,7 +262,7 @@ module Ebooks
if ev.is_a? Twitter::DirectMessage if ev.is_a? Twitter::DirectMessage
return if blacklisted?(ev.sender.screen_name) return if blacklisted?(ev.sender.screen_name)
log "Sending DM to @#{ev.sender.screen_name}: #{text}" log "Sending DM to @#{ev.sender.screen_name}: #{text}"
@twitter.create_direct_message(ev.sender.screen_name, text, opts) twitter.create_direct_message(ev.sender.screen_name, text, opts)
elsif ev.is_a? Twitter::Tweet elsif ev.is_a? Twitter::Tweet
meta = calc_meta(ev) meta = calc_meta(ev)
@ -258,17 +271,17 @@ module Ebooks
return return
end end
if !meta[:mentions_bot] && !userinfo(ev.user.screen_name).can_pester? if !meta[:mentions_bot]
log "Already pestered @#{ev.user.screen_name} enough for now" if !userinfo(ev.user.screen_name).can_pester?
log "Not replying: leaving @#{ev.user.screen_name} alone"
return return
else
userinfo(ev.user.screen_name).pesters_left -= 1
end
end end
log "Replying to @#{ev.user.screen_name} with: #{meta[:reply_prefix] + text}" log "Replying to @#{ev.user.screen_name} with: #{meta[:reply_prefix] + text}"
@twitter.update(meta[:reply_prefix] + text, in_reply_to_status_id: ev.id) twitter.update(meta[:reply_prefix] + text, in_reply_to_status_id: ev.id)
meta[:reply_mentions].each do |username|
userinfo(username).pester_count += 1
end
else else
raise Exception("Don't know how to reply to a #{ev.class}") raise Exception("Don't know how to reply to a #{ev.class}")
end end
@ -278,8 +291,13 @@ module Ebooks
return if blacklisted?(tweet.user.screen_name) return if blacklisted?(tweet.user.screen_name)
log "Favoriting @#{tweet.user.screen_name}: #{tweet.text}" log "Favoriting @#{tweet.user.screen_name}: #{tweet.text}"
meta = calc_meta(tweet)
if !meta[:mentions_bot] && !userinfo(ev.user.screen_name).can_pester?
log "Not favoriting: leaving @#{ev.user.screen_name} alone"
end
begin begin
@twitter.favorite(tweet.id) twitter.favorite(tweet.id)
rescue Twitter::Error::Forbidden rescue Twitter::Error::Forbidden
log "Already favorited: #{tweet.user.screen_name}: #{tweet.text}" log "Already favorited: #{tweet.user.screen_name}: #{tweet.text}"
end end
@ -290,7 +308,7 @@ module Ebooks
log "Retweeting @#{tweet.user.screen_name}: #{tweet.text}" log "Retweeting @#{tweet.user.screen_name}: #{tweet.text}"
begin begin
@twitter.retweet(tweet.id) twitter.retweet(tweet.id)
rescue Twitter::Error::Forbidden rescue Twitter::Error::Forbidden
log "Already retweeted: #{tweet.user.screen_name}: #{tweet.text}" log "Already retweeted: #{tweet.user.screen_name}: #{tweet.text}"
end end
@ -298,13 +316,12 @@ module Ebooks
def follow(*args) def follow(*args)
log "Following #{args}" log "Following #{args}"
twitter.follow(*args)
@twitter.follow(*args)
end end
def tweet(*args) def tweet(*args)
log "Tweeting #{args.inspect}" log "Tweeting #{args.inspect}"
@twitter.update(*args) twitter.update(*args)
end end
def scheduler def scheduler
@ -314,7 +331,7 @@ module Ebooks
# could easily just be *args however the separation keeps it clean. # could easily just be *args however the separation keeps it clean.
def pictweet(txt, pic, *args) def pictweet(txt, pic, *args)
log "Tweeting #{txt.inspect} - #{pic} #{args}" log "Tweeting #{txt.inspect} - #{pic} #{args}"
@twitter.update_with_media(txt, File.new(pic), *args) twitter.update_with_media(txt, File.new(pic), *args)
end end
end end
end end