:validate => Proc.new { |v| v >= 0 },
:desc => "Time the learning thread spends sleeping after learning a line. If set to zero, learning from files can be very CPU intensive, but also faster.")
Config.register Config::IntegerValue.new('markov.delay',
- :default => true,
+ :default => 5,
:validate => Proc.new { |v| v >= 0 },
:desc => "Wait short time before contributing to conversation.")
Config.register Config::IntegerValue.new('markov.answer_addressed',
@upgrade_queue.push nil
@upgrade_thread = Thread.new do
+ @registry.recovery = Proc.new { |val|
+ return [val]
+ }
logfile = File.open(@bot.path('markov-conversion.log'), 'a')
logfile.puts "=== conversion thread started #{Time.now} ==="
while k = @upgrade_queue.pop
end
logfile.puts "=== conversion thread stopped #{Time.now} ==="
logfile.close
+ @registry.recovery = nil
end
@upgrade_thread.priority = -1
end
@chains.set_default([])
@rchains = @registry.sub_registry('v2r')
@rchains.set_default([])
+ @chains_mutex = Mutex.new
+ @rchains_mutex = Mutex.new
@upgrade_queue = Queue.new
@upgrade_thread = nil
output = word1
keys = []
@chains.each_key(output) do |key|
- if key.downcase.include? output
- keys << key
- else
- break
- end
+ if key.downcase.include? output
+ keys << key
+ else
+ break
+ end
end
return nil if keys.empty?
output = keys[rand(keys.size)].split(/ /)
- end
+ end
output = output.split(/ /) unless output.is_a? Array
input = [word1, word2]
while output.length < @bot.config['markov.max_words'] and (output.first != MARKER or output.last != MARKER) do
if output == input
nil
else
- output.join(" ")
- end
+ output.join(" ")
+ end
end
def help(plugin, topic="")
else
"markov chat => try to say something intelligent"
end
+ when "learn"
+ ["markov learn from <file> [testing [<num> lines]] [using pattern <pattern>]:",
+ "learn from the text in the specified <file>, optionally using the given <pattern> to filter the text.",
+ "you can sample what would be learned by specifying 'testing <num> lines'"].join(' ')
else
- "markov plugin: listens to chat to build a markov chain, with which it can (perhaps) attempt to (inanely) contribute to 'discussion'. Sort of.. Will get a *lot* better after listening to a lot of chat. Usage: 'chat' to attempt to say something relevant to the last line of chat, if it can -- help topics: ignore, readonly, delay, status, probability, chat, chat about"
+ "markov plugin: listens to chat to build a markov chain, with which it can (perhaps) attempt to (inanely) contribute to 'discussion'. Sort of.. Will get a *lot* better after listening to a lot of chat. Usage: 'chat' to attempt to say something relevant to the last line of chat, if it can -- help topics: ignore, readonly, delay, status, probability, chat, chat about, learn"
end
end
- def clean_str(s)
- str = s.dup
- str.gsub!(/^\S+[:,;]/, "")
+ def clean_message(m)
+ str = m.plainmessage.dup
+ str =~ /^(\S+)([:,;])/
+ if $1 and m.target.is_a? Irc::Channel and m.target.user_nicks.include? $1.downcase
+ str.gsub!(/^(\S+)([:,;])\s+/, "")
+ end
str.gsub!(/\s{2,}/, ' ') # fix for two or more spaces
return str.strip
end
def status(m,params)
if @bot.config['markov.enabled']
- reply = _("markov is currently enabled, %{p}% chance of chipping in") % { :p => probability? }
+ reply = _("markov is currently enabled, %{p}%% chance of chipping in") % { :p => probability? }
l = @learning_queue.length
reply << (_(", %{l} messages in queue") % {:l => l}) if l > 0
l = @upgrade_queue.length
@bot.config['markov.probability'] = params[:probability].to_i
m.okay
else
- m.reply _("markov has a %{prob}% chance of chipping in") % { :prob => probability? }
+ m.reply _("markov has a %{prob}%% chance of chipping in") % { :prob => probability? }
end
end
m.okay
end
- def should_talk
+ def should_talk(m)
return false unless @bot.config['markov.enabled']
- prob = probability?
+ prob = m.address? ? @bot.config['markov.answer_addressed'] : probability?
return true if prob > rand(100)
return false
end
def reply_delay(m, line)
m.replied = true
if @bot.config['markov.delay'] > 0
- @bot.timer.add_once(@bot.config['markov.delay']) {
+ @bot.timer.add_once(1 + rand(@bot.config['markov.delay'])) {
m.reply line, :nick => false, :to => :public
}
else
end
def random_markov(m, message)
- return unless (should_talk or (m.address? and @bot.config['markov.answer_addressed'] > rand(100)))
+ return unless should_talk(m)
- words = clean_str(message).split(/\s+/)
+ words = clean_message(m).split(/\s+/)
if words.length < 2
line = generate_string words.first, nil
end
random_markov(m, message) unless readonly? m or m.replied?
- learn message
+ learn clean_message(m)
end
def learn_triplet(word1, word2, word3)
k = "#{word1} #{word2}"
rk = "#{word2} #{word3}"
- total = 0
- hash = Hash.new(0)
- if @chains.key? k
- t2, h2 = @chains[k]
- total += t2
- hash.update h2
+ @chains_mutex.synchronize do
+ total = 0
+ hash = Hash.new(0)
+ if @chains.key? k
+ t2, h2 = @chains[k]
+ total += t2
+ hash.update h2
+ end
+ hash[word3] += 1
+ total += 1
+ @chains[k] = [total, hash]
end
- hash[word3] += 1
- total += 1
- @chains[k] = [total, hash]
- # Reverse
- total = 0
- hash = Hash.new(0)
- if @rchains.key? rk
- t2, h2 = @rchains[rk]
- total += t2
- hash.update h2
+ @rchains_mutex.synchronize do
+ # Reverse
+ total = 0
+ hash = Hash.new(0)
+ if @rchains.key? rk
+ t2, h2 = @rchains[rk]
+ total += t2
+ hash.update h2
+ end
+ hash[word1] += 1
+ total += 1
+ @rchains[rk] = [total, hash]
end
- hash[word1] += 1
- total += 1
- @rchains[rk] = [total, hash]
end
def learn_line(message)
# debug "learning #{message.inspect}"
- wordlist = clean_str(message).split(/\s+/).reject do |w|
+ wordlist = message.strip.split(/\s+/).reject do |w|
@bot.config['markov.ignore_patterns'].map do |pat|
w =~ Regexp.new(pat.to_s)
end.select{|v| v}.size != 0
plugin.map 'markov disable', :action => "disable"
plugin.map 'markov status', :action => "status"
plugin.map 'markov stats', :action => "stats"
-plugin.map 'chat about :seed1 [:seed2]', :action => "chat"
+plugin.map 'chat about :seed1 [:seed2]', :action => "chat", :defaults => {:seed2 => nil}
plugin.map 'chat', :action => "rand_chat"
plugin.map 'markov probability [:probability]', :action => "probability",
+ :defaults => {:probability => nil},
:requirements => {:probability => /^\d+%?$/}
plugin.map 'markov learn from :file [:testing [:lines lines]] [using pattern *pattern]', :action => "learn_from", :thread => true,
:requirements => {