Class: MegaHAL
- Inherits:
-
Object
- Object
- MegaHAL
- Defined in:
- lib/megahal/keyword.rb,
lib/megahal/megahal.rb
Constant Summary collapse
- GREETING =
["G'DAY", "GREETINGS", "HELLO", "HULLO", "HI", "HOWDY", "WELCOME"]
- ANTONYMS =
[ ["DISLIKE", "LIKE"], ["HATE", "LOVE"], ["I", "YOU"], ["I'D", "YOU'D"], ["I'LL", "YOU'LL"], ["I'M", "YOU'RE"], ["I'VE", "YOU'VE"], ["LIKE", "DISLIKE"], ["LOVE", "HATE"], ["ME", "YOU"], ["MINE", "YOURS"], ["MY", "YOUR"], ["MYSELF", "YOURSELF"], ["NO", "YES"], ["WHY", "BECAUSE"], ["YES", "NO"], ["YOU", "I"], ["YOU", "ME"], ["YOU'D", "I'D"], ["YOU'LL", "I'LL"], ["YOU'RE", "I'M"], ["YOU'VE", "I'VE"], ["YOUR", "MY"], ["YOURS", "MINE"], ["YOURSELF", "MYSELF"], ["HOLMES", "WATSON"], ["FRIEND", "ENEMY"], ["ALIVE", "DEAD"], ["LIFE", "DEATH"], ["QUESTION", "ANSWER"], ["BLACK", "WHITE"], ["COLD", "HOT"], ["HAPPY", "SAD"], ["FALSE", "TRUE"], ["HEAVEN", "HELL"], ["GOD", "DEVIL"], ["NOISY", "QUIET"], ["WAR", "PEACE"], ["SORRY", "APOLOGY"] ]
- SWAP =
- AUXILIARY =
" DISLIKE\n HE\n HER\n HERS\n HIM\n HIS\n I\n I'D\n I'LL\n I'M\n I'VE\n LIKE\n ME\n MINE\n MY\n MYSELF\n ONE\n SHE\n THREE\n TWO\n YOU\n YOU'D\n YOU'LL\n YOU'RE\n YOU'VE\n YOUR\n YOURS\n YOURSELF\n".each_line.to_a.map(&:strip)
- BANNED =
" A\n ABILITY\n ABLE\n ABOUT\n ABSOLUTE\n ABSOLUTELY\n ACROSS\n ACTUAL\n ACTUALLY\n AFTER\n AFTERNOON\n AGAIN\n AGAINST\n AGO\n AGREE\n ALL\n ALMOST\n ALONG\n ALREADY\n ALTHOUGH\n ALWAYS\n AM\n AN\n AND\n ANOTHER\n ANY\n ANYHOW\n ANYTHING\n ANYWAY\n ARE\n AREN'T\n AROUND\n AS\n AT\n AWAY\n BACK\n BAD\n BE\n BEEN\n BEFORE\n BEHIND\n BEING\n BELIEVE\n BELONG\n BEST\n BETTER\n BETWEEN\n BIG\n BIGGER\n BIGGEST\n BIT\n BOTH\n BUDDY\n BUT\n BY\n CALL\n CALLED\n CALLING\n CAME\n CAN\n CAN'T\n CANNOT\n CARE\n CARING\n CASE\n CATCH\n CAUGHT\n CERTAIN\n CERTAINLY\n CHANGE\n CLOSE\n CLOSER\n COME\n COMING\n COMMON\n CONSTANT\n CONSTANTLY\n COULD\n CURRENT\n DAY\n DAYS\n DERIVED\n DESCRIBE\n DESCRIBES\n DETERMINE\n DETERMINES\n DID\n DIDN'T\n DO\n DOES\n DOESN'T\n DOING\n DON'T\n DONE\n DOUBT\n DOWN\n EACH\n EARLIER\n EARLY\n ELSE\n ENJOY\n ESPECIALLY\n EVEN\n EVER\n EVERY\n EVERYBODY\n EVERYONE\n EVERYTHING\n FACT\n FAIR\n FAIRLY\n FAR\n FELLOW\n FEW\n FIND\n FINE\n FOR\n FORM\n FOUND\n FROM\n FULL\n FURTHER\n GAVE\n GET\n GETTING\n GIVE\n GIVEN\n GIVING\n GO\n GOING\n GONE\n GOOD\n GOT\n GOTTEN\n GREAT\n HAD\n HAS\n HASN'T\n HAVE\n HAVEN'T\n HAVING\n HELD\n HERE\n HIGH\n HOLD\n HOLDING\n HOW\n IF\n IN\n INDEED\n INSIDE\n INSTEAD\n INTO\n IS\n ISN'T\n IT\n IT'S\n ITS\n JUST\n KEEP\n KIND\n KNEW\n KNOW\n KNOWN\n LARGE\n LARGER\n LARGETS\n LAST\n LATE\n LATER\n LEAST\n LESS\n LET\n LET'S\n LEVEL\n LIKES\n LITTLE\n LONG\n LONGER\n LOOK\n LOOKED\n LOOKING\n LOOKS\n LOW\n MADE\n MAKE\n MAKING\n MANY\n MATE\n MAY\n MAYBE\n MEAN\n MEET\n MENTION\n MERE\n MIGHT\n MOMENT\n MORE\n MORNING\n MOST\n MOVE\n MUCH\n MUST\n NEAR\n NEARER\n NEVER\n NEXT\n NICE\n NOBODY\n NONE\n NOON\n NOONE\n NOT\n NOTE\n NOTHING\n NOW\n OBVIOUS\n OF\n OFF\n ON\n ONCE\n ONLY\n ONTO\n OPINION\n OR\n OTHER\n OUR\n OUT\n OVER\n OWN\n PART\n PARTICULAR\n PARTICULARLY\n PERHAPS\n PERSON\n PIECE\n PLACE\n PLEASANT\n PLEASE\n POPULAR\n PREFER\n PRETTY\n PUT\n QUITE\n REAL\n REALLY\n RECEIVE\n RECEIVED\n RECENT\n RECENTLY\n RELATED\n RESULT\n RESULTING\n RESULTS\n SAID\n SAME\n SAW\n SAY\n SAYING\n SEE\n SEEM\n SEEMED\n SEEMS\n SEEN\n SELDOM\n SENSE\n SET\n SEVERAL\n SHALL\n SHORT\n SHORTER\n SHOULD\n SHOW\n SHOWS\n SIMPLE\n SIMPLY\n SMALL\n SO\n SOME\n SOMEONE\n SOMETHING\n SOMETIME\n SOMETIMES\n SOMEWHERE\n SORT\n SORTS\n SPEND\n SPENT\n STILL\n STUFF\n SUCH\n SUGGEST\n SUGGESTION\n SUPPOSE\n SURE\n SURELY\n SURROUND\n SURROUNDS\n TAKE\n TAKEN\n TAKING\n TELL\n THAN\n THANK\n THANKS\n THAT\n THAT'S\n THATS\n THE\n THEIR\n THEM\n THEN\n THERE\n THEREFORE\n THESE\n THEY\n THING\n THINGS\n THIS\n THOSE\n THOUGH\n THOUGHTS\n THOUROUGHLY\n THROUGH\n TINY\n TO\n TODAY\n TOGETHER\n TOLD\n TOMORROW\n TOO\n TOTAL\n TOTALLY\n TOUCH\n TRY\n TWICE\n UNDER\n UNDERSTAND\n UNDERSTOOD\n UNTIL\n UP\n US\n USED\n USING\n USUALLY\n VARIOUS\n VERY\n WANT\n WANTED\n WANTS\n WAS\n WATCH\n WAY\n WAYS\n WE\n WE'RE\n WELL\n WENT\n WERE\n WHAT\n WHAT'S\n WHATEVER\n WHATS\n WHEN\n WHERE\n WHERE'S\n WHICH\n WHILE\n WHILST\n WHO\n WHO'S\n WHOM\n WILL\n WISH\n WITH\n WITHIN\n WONDER\n WONDERFUL\n WORSE\n WORST\n WOULD\n WRONG\n YESTERDAY\n YET\n".each_line.to_a.map(&:strip)
Instance Attribute Summary collapse
-
#learning ⇒ Object
Returns the value of attribute learning.
Class Method Summary collapse
- .add_personality(name, data) ⇒ Object
-
.extract(words) ⇒ Object
This takes an array of capitalised (normalised) words, and returns an array of keywords (which simply remove banned words, and switch some words with their antonyms).
-
.list ⇒ Array
Returns an array of MegaHAL personalities.
Instance Method Summary collapse
-
#become(name = :default, bar = nil) ⇒ Object
Loads the specified personality.
-
#clear ⇒ Object
Wipe MegaHAL’s brain.
-
#initialize ⇒ MegaHAL
constructor
Create a new MegaHAL instance, loading the :default personality.
- #inspect ⇒ Object
-
#load(filename, bar = nil) ⇒ Object
Load a brain that has previously been saved.
-
#reply(input, error = "...") ⇒ String
Generate a reply to the user’s input.
-
#save(filename, bar = nil) ⇒ Object
Save MegaHAL’s brain to the specified binary file.
-
#train(filename, bar = nil) ⇒ Object
Train MegaHAL with the contents of the specified file, which should be plain text with one sentence per line.
Constructor Details
#initialize ⇒ MegaHAL
Create a new MegaHAL instance, loading the :default personality.
11 12 13 14 15 16 17 18 19 |
# File 'lib/megahal/megahal.rb', line 11 def initialize @learning = true @seed = Sooth::Predictor.new(0) @fore = Sooth::Predictor.new(0) @back = Sooth::Predictor.new(0) @case = Sooth::Predictor.new(0) @punc = Sooth::Predictor.new(0) become(:default) end |
Instance Attribute Details
#learning ⇒ Object
Returns the value of attribute learning.
8 9 10 |
# File 'lib/megahal/megahal.rb', line 8 def learning @learning end |
Class Method Details
.add_personality(name, data) ⇒ Object
38 39 40 41 42 |
# File 'lib/megahal/megahal.rb', line 38 def self.add_personality(name, data) @@personalities ||= {} @@personalities[name.to_sym] = data.each_line.to_a nil end |
.extract(words) ⇒ Object
This takes an array of capitalised (normalised) words, and returns an array of keywords (which simply remove banned words, and switch some words with their antonyms). This exists purely to emulate the original MegaHAL. It would be better if keywords were learned by observing question-answer pairs.
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# File 'lib/megahal/keyword.rb', line 6 def self.extract(words) return GREETING if words.nil? words .map do |word| if word =~ /^[0-9]/ nil elsif BANNED.include?(word) nil elsif SWAP.key?(word) SWAP[word] else word end end .compact .uniq end |
.list ⇒ Array
Returns an array of MegaHAL personalities.
47 48 49 50 |
# File 'lib/megahal/megahal.rb', line 47 def self.list @@personalities ||= {} @@personalities.keys end |
Instance Method Details
#become(name = :default, bar = nil) ⇒ Object
Loads the specified personality. Will raise an exception if the personality parameter isn’t one of those returned by #list. Note that this will clear MegaHAL’s brain first.
58 59 60 61 62 63 |
# File 'lib/megahal/megahal.rb', line 58 def become(name=:default, = nil) raise ArgumentError, "no such personality" unless @@personalities.key?(name) clear .total = @@personalities[name].length unless .nil? _train(@@personalities[name], ) end |
#clear ⇒ Object
Wipe MegaHAL’s brain. Note that this wipes the personality too, allowing you to begin from a truly blank slate.
27 28 29 30 31 32 33 34 35 36 |
# File 'lib/megahal/megahal.rb', line 27 def clear @seed.clear @fore.clear @back.clear @case.clear @punc.clear @dictionary = { "<error>" => 0, "<fence>" => 1, "<blank>" => 2 } @brain = {} nil end |
#inspect ⇒ Object
21 22 23 |
# File 'lib/megahal/megahal.rb', line 21 def inspect to_s end |
#load(filename, bar = nil) ⇒ Object
Load a brain that has previously been saved.
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/megahal/megahal.rb', line 138 def load(filename, = nil) .total = 6 unless .nil? Zip::File.open(filename) do |zipfile| data = Marshal::load(zipfile.find_entry("dictionary").get_input_stream.read) raise "bad version" unless data[:version] == "MH11" @learning = data[:learning] @brain = data[:brain] @dictionary = data[:dictionary] .increment unless .nil? [:seed, :fore, :back, :case, :punc].each do |name| tmp = _get_tmp_filename(name) zipfile.find_entry(name.to_s).extract(tmp) instance_variable_get("@#{name}").load(tmp) .increment unless .nil? end end end |
#reply(input, error = "...") ⇒ String
Generate a reply to the user’s input. If the learning attribute is set to true, MegaHAL will also learn from what the user said. Note that it takes MegaHAL about one second to generate about 500 replies.
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/megahal/megahal.rb', line 77 def reply(input, error="...") puncs, norms, words = _decompose(input ? input.strip : nil) keyword_symbols = MegaHAL.extract(norms) .map { |keyword| @dictionary[keyword] } .compact input_symbols = (norms || []).map { |norm| @dictionary[norm] } # create candidate utterances utterances = [] 9.times { utterances << _generate(keyword_symbols) } utterances << _generate([]) utterances.delete_if { |utterance| utterance == input_symbols } utterances.compact! # select the best utterance, and handle _rewrite failure reply = nil while reply.nil? && utterances.length > 0 break unless utterance = _select_utterance(utterances, keyword_symbols) reply = _rewrite(utterance) utterances.delete(utterance) end # learn from what the user said _after_ generating the reply _learn(puncs, norms, words) if @learning && norms return reply || error end |
#save(filename, bar = nil) ⇒ Object
Save MegaHAL’s brain to the specified binary file.
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/megahal/megahal.rb', line 112 def save(filename, = nil) .total = 6 unless .nil? Zip::File.open(filename, Zip::File::CREATE) do |zipfile| zipfile.get_output_stream("dictionary") do |file| data = { version: 'MH11', learning: @learning, brain: @brain, dictionary: @dictionary } file.write(Marshal::dump(data)) end .increment unless .nil? [:seed, :fore, :back, :case, :punc].each do |name| tmp = _get_tmp_filename(name) instance_variable_get("@#{name}").save(tmp) zipfile.add(name, tmp) .increment unless .nil? end end end |
#train(filename, bar = nil) ⇒ Object
Train MegaHAL with the contents of the specified file, which should be plain text with one sentence per line. Note that it takes MegaHAL about one second to process about 500 lines, so large files may cause the process to block for a while. Lines that are too long will be skipped.
163 164 165 166 167 |
# File 'lib/megahal/megahal.rb', line 163 def train(filename, = nil) lines = File.read(filename).each_line.to_a .total = lines.length unless .nil? _train(lines, ) end |