mirror of
https://github.com/thewesker/ebooks_example.git
synced 2025-12-20 04:11:13 -05:00
3.0.0 update
This commit is contained in:
224
bots.rb
224
bots.rb
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user