# Submits input asynchronously to agents, then loops through their responses # until it finds a high scoring response, or until a time limit is reached. # The alternate require paths are relative to the redturnip root directory. begin require 'gagent'; rescue LoadError; require 'mod/bot/gagent'; end begin require 'aliceagent'; rescue LoadError; require 'mod/bot/aliceagent'; end #begin require 'mathetesagent'; rescue LoadError; require 'mod/bot/mathetesagent'; end begin require 'wnagent'; rescue LoadError; require 'mod/bot/wnagent'; end begin require 'linkagent'; rescue LoadError; require 'mod/bot/linkagent'; end begin require 'megahalagent'; rescue LoadError; require 'mod/bot/megahalagent'; end begin require 'montyagent'; rescue LoadError; require 'mod/bot/montyagent'; end begin require 'isragent'; rescue LoadError; require 'mod/bot/isragent'; end begin require 'lingagent'; rescue LoadError; require 'mod/bot/lingagent'; end begin require 'bcagent'; rescue LoadError; require 'mod/bot/bcagent'; end begin require 'sumagent'; rescue LoadError; require 'mod/bot/sumagent'; end begin require 'emoagent'; rescue LoadError; require 'mod/bot/emoagent'; end begin require 'oppagent'; rescue LoadError; require 'mod/bot/oppagent'; end begin require 'logicwrapper'; rescue LoadError; require 'mod/bot/logicwrapper'; end begin require 'ifwrapper'; rescue LoadError; require 'mod/bot/ifwrapper'; end begin require 'testwrapper'; rescue LoadError; require 'mod/bot/testwrapper'; end begin require 'restartwrapper'; rescue LoadError; require 'mod/bot/restartwrapper'; end begin require 'lppagent'; rescue LoadError; require 'mod/bot/lppagent'; end begin require 'dpagentwrapper'; rescue LoadError; require 'mod/bot/dpagentwrapper'; end begin require 'todoagentwrapper'; rescue LoadError; require 'mod/bot/todoagentwrapper'; end BasicSocket.do_not_reverse_lookup = true # To make DRb.start_service faster class Controller attr_accessor :MY_NAME, :DEBUG, :DELAY, :SLEEP def initialize @gagent = GAgent.new(self) # port 9011 @logic = LogicAgentWrapper.new(self) # port 9012 @alice = ALICEAgent.new(self) # port 9020 #@mathetes = MathetesAgent.new(self) # port 9030 @wnbot = WNAgent.new(self) # port 9040 @link = LinkAgent.new(self) # port 9050 @megahal = MegaHALAgent.new(self) # port 9060 @monty = MontyAgent.new(self) # port 9070 @isr = ISRAgent.new(self) # port 9080 @ling = LingAgent.new(self) # port 9090 @bc = BCAgent.new(self) # port 9100 @sum = SumAgent.new(self) # port 9110 @opp = OppAgent.new(self) # port 9120 @emo = EmoAgent.new(self) # port 9130 @if = IfAgentWrapper.new(self) # port 9131 @test = TestAgentWrapper.new(self) # port 9140 @restart = RestartAgentWrapper.new(self) # port 9150 @lpp = LppAgent.new(self) @dp = DPAgentWrapper.new(self) # port 9160 @todo = TodoAgentWrapper.new(self) # port 9170 @agent_array = [ @gagent, @alice, @wnbot, @link, #@mathetes, @megahal, @monty, @isr, @ling, @bc, @sum, @emo, @opp, @if, @logic, @test, @restart, @lpp, @dp, @todo ] @response_array = Array.new @THRESHOLD = 1 @SLEEP = 2 # how long the poll loop sleeps each time through @DELAY = 5 # maximum seconds to wait before returning a response @MY_NAME = "(?i)(controller|controlbot|controlagent)" @DEBUG = 0 @last_response = '' @negative_feedback = Array.new @negative_feedback.push("you suck", "that response suck") @positive_feedback.push("nice") @positive_feedback.push("good one") @positive_feedback.push("haha") puts "\nReading remember.txt..." read_file("remember.txt") # load "remember: ___" commands puts "\nHello" end def check_for_preprocessing_commands(input) case input when /add (.*) (?:to|as) negative feedback(.*)/i grp1 = process $1; grp2 = process $2 save = true puts "[controller].check_for_preprocessing_commands: grp2==#{grp2}" if grp2 =~ /.*do.*n.*t.*save/ then save = false end puts "[controller] save==#{save}" @negative_feedback.push(grp1) # add to this file if save file = IO.read(__FILE__) #puts "file==#{file}" case file when /(.*?)(@negative_feedback.push\(.*?\))(.*)/m g1 = $1; g2 = $2; g3 = $3 newfile = g1 + g2 + "\n @negative_feedback.push(\"#{grp1}\")" + g3 File.open("controller.rb", "w+") { |f| f.puts newfile } end # case end # if return "Okay" when /delete (.*) from negative feedback/i grp1 = process $1 @negative_feedback.delete(grp1) # TODO: delete from this file return "Okay" when /show negative feedback/i return @negative_feedback.join('|') when /^#{@negative_feedback.join('|')}/i # write to log File.open("feedback.txt", "a+") { |f| s = Regexp.escape(@last_response[0].strip) f.puts "#{@last_response[2]}: if response =~ /#{s}/ then score -= 1 end" } return getResponse("#{@last_response[2]}: if response =~ /#{@last_response[0].strip}/ then score -= 1 end") when /add (.*) (?:to|as) positive feedback(.*)/i, /positive feedback: (.*)/ grp1 = process $1; grp2 = process $2 save = true if grp2 =~ /.*do.*n.*t.*save/ then save = false end @positive_feedback.push(grp1) # add to this file if save file = IO.read(__FILE__) #puts "file==#{file}" case file when /(.*?)(@positive_feedback.push\(.*?\))(.*)/m g1 = $1; g2 = $2; g3 = $3 newfile = g1 + g2 + "\n @positive_feedback.push(\"#{grp1}\")" + g3 File.open("controller.rb", "w+") { |f| f.puts newfile } end # case end # if return "Okay" when /delete (.*) from positive feedback/i grp1 = process $1 @positive_feedback.delete(grp1) # TODO: delete from this file return "Okay" when /^(#{@positive_feedback.join('|')})$/i # write to log File.open("feedback.txt", "a+") { |f| f.puts "#{@last_response[2]}: if response =~ /#{@last_response[0].strip}/ then score += 1 end" } return getResponse("#{@last_response[2]}: if response =~ /#{@last_response[0].strip}/ then score += 1 end") when /show positive feedback/i, /show.*positive.*feedback/i return @positive_feedback.join('|') when /read feedback file/i, /read.*feedback.*file/i, /read.*feedback/i return read_feedback_file when /who said that/i, /wh.*agent.*that/i, /wh.*said.*it/i return @last_response[2].to_s when /what was the score/i, /wh.*score/i return @last_response[1].to_s when /remember that (.*)/i, /remember (.*)/i, /remember: (.*)/i grp1 = $1.to_s File.open("remember.txt", "a+") { |f| f.puts(grp1) } return getResponse(grp1) end # case end # check_for_preprocessing_commands def read_feedback_file read_file("feedback.txt") end def read_file(file = 'feedback.txt') count = 0 begin IO.foreach(file) { |statement| if statement =~ /^#/ then next end if statement.strip == '' then next end count += 1 puts "#{count}: #{statement}" response = getResponse(statement) puts response unless @DEBUG == 0 } rescue => boom return boom end s = 's'; if count == 1 then s = '' end return "Okay, #{file} read: #{count} statement#{s}." end # Strips delimiters. def process str if str.class != String then return '' end str.strip! str.sub!(/\?$/, '') str.sub!(/^\[/, '') str.sub!(/\]$/, '') str.sub!(/^(?:"|')/, '') str.sub!(/(?:"|')$/, '') str.sub!(/\.$/, '') str.sub!(/;$/, '') str.sub!(/,$/, '') str.sub!(/!$/, '') str.sub!(/\?$/, '') return str end def getResponse(input = "") r = check_for_preprocessing_commands(input) #puts "r==#{r}" if r != nil then return r end @response_array = [] submitInput(input) total_seconds = 0 some_response = ["Default response from controller."] max_so_far = 0 # Keep a count to ensure that the loop executes at least once before # the top-scoring response is determined: count = 0 # Every few seconds, loop through @response_array looking for # high-scoring responses. loop { count += 1 #puts "#{@SLEEP}, #{@DELAY}" sleep(@SLEEP.to_f) #puts @response_array.inspect @response_array.each { |response| #puts "response==#{response}" score = response[1] rescue score = 1 if input =~ /#{@MY_NAME}[:,!]* (.*)/ then score += 2 end response[1] = score if max_so_far > @THRESHOLD and count > 1 @last_response = some_response #puts "1. @last_response==#{@last_response}" return some_response end if score > max_so_far some_response = response max_so_far = score next end } total_seconds += @SLEEP.to_f if total_seconds > @DELAY.to_f @last_response = some_response #puts "2. @last_response==#{@last_response}" return some_response end } end # Send input asynchronously to agents. def submitInput(input) if input =~ /#{@MY_NAME}[:,!]* (.*)/ then input = $1 end @agent_array.each { |agent| Thread.new(agent) { |myagent| myagent.send(input) } # if input =~ an agent name, send it to that agent only # begin # if input =~ /#{agent.MY_NAME}[:,!]* / then break end # rescue # puts "error!" # end } end # Callback for agents. def addResponse(response) if response.size == 2 then response.push("unknown") end #puts "addResponse called with: #{response}" @response_array.push(response) end end if $0 == __FILE__ c = Controller.new print "\n> "; $stdout.flush quitwords = [":q", "quit", "exit", "bye"] while (line = gets) !~ /^#{quitwords.join('|')}$/ and line !~ /^$/ response = c.getResponse(line.to_s).to_s + "\n\n" print "\n#{response}" print "> "; $stdout.flush end puts "Bye" end