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

224
bots.rb
View File

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