megahal 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: af7cea408577bbc60da09d9ea222afc32fb0624c
4
+ data.tar.gz: f27c277b75969c4a7bcd94fe6a0de4c56fa68988
5
+ SHA512:
6
+ metadata.gz: f62986be611257ee349cbc4f48d4e4e170ba94c0853240f592bfdcae63601b7826ac6764391c06085730885e1c415b2040fe0b6d78e7711c1d92be29f290c491
7
+ data.tar.gz: c1ac5d103372d12a53c8e4d3d8173537fba9730241fc1f0b65cd8db3d99e8e04a083507c077b89e8a6a3b02017fc2c9f7f75d1f86433f0c567020d7e038808f8
data/Gemfile ADDED
@@ -0,0 +1,18 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'sooth', '~> 1.0'
4
+ gem 'highline', '~> 1.6'
5
+ gem 'hodel_3000_compliant_logger', '~> 0.1'
6
+ gem 'ruby-progressbar', '~> 1.7'
7
+ gem 'rubyzip', '~> 1.1'
8
+ gem 'cld', '~> 0.7'
9
+
10
+ group :development do
11
+ gem 'rspec', '~> 3.1'
12
+ gem 'yard', '~> 0.8'
13
+ gem 'rdoc', '~> 4.1'
14
+ gem 'bundler', '~> 1.7'
15
+ gem 'jeweler', '~> 2.0'
16
+ gem 'simplecov', '~> 0.9'
17
+ gem 'byebug', '~> 3.5'
18
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,100 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ addressable (2.3.6)
5
+ builder (3.2.2)
6
+ byebug (3.5.1)
7
+ columnize (~> 0.8)
8
+ debugger-linecache (~> 1.2)
9
+ slop (~> 3.6)
10
+ cld (0.7.0)
11
+ ffi
12
+ columnize (0.9.0)
13
+ debugger-linecache (1.2.0)
14
+ descendants_tracker (0.0.4)
15
+ thread_safe (~> 0.3, >= 0.3.1)
16
+ diff-lcs (1.2.5)
17
+ docile (1.1.5)
18
+ faraday (0.9.0)
19
+ multipart-post (>= 1.2, < 3)
20
+ ffi (1.9.6)
21
+ git (1.2.8)
22
+ github_api (0.12.2)
23
+ addressable (~> 2.3)
24
+ descendants_tracker (~> 0.0.4)
25
+ faraday (~> 0.8, < 0.10)
26
+ hashie (>= 3.3)
27
+ multi_json (>= 1.7.5, < 2.0)
28
+ nokogiri (~> 1.6.3)
29
+ oauth2
30
+ hashie (3.3.2)
31
+ highline (1.6.21)
32
+ hodel_3000_compliant_logger (0.1.1)
33
+ jeweler (2.0.1)
34
+ builder
35
+ bundler (>= 1.0)
36
+ git (>= 1.2.5)
37
+ github_api
38
+ highline (>= 1.6.15)
39
+ nokogiri (>= 1.5.10)
40
+ rake
41
+ rdoc
42
+ json (1.8.1)
43
+ jwt (1.2.0)
44
+ mini_portile (0.6.1)
45
+ multi_json (1.10.1)
46
+ multi_xml (0.5.5)
47
+ multipart-post (2.0.0)
48
+ nokogiri (1.6.5)
49
+ mini_portile (~> 0.6.0)
50
+ oauth2 (1.0.0)
51
+ faraday (>= 0.8, < 0.10)
52
+ jwt (~> 1.0)
53
+ multi_json (~> 1.3)
54
+ multi_xml (~> 0.5)
55
+ rack (~> 1.2)
56
+ rack (1.5.2)
57
+ rake (10.4.2)
58
+ rdoc (4.2.0)
59
+ json (~> 1.4)
60
+ rspec (3.1.0)
61
+ rspec-core (~> 3.1.0)
62
+ rspec-expectations (~> 3.1.0)
63
+ rspec-mocks (~> 3.1.0)
64
+ rspec-core (3.1.7)
65
+ rspec-support (~> 3.1.0)
66
+ rspec-expectations (3.1.2)
67
+ diff-lcs (>= 1.2.0, < 2.0)
68
+ rspec-support (~> 3.1.0)
69
+ rspec-mocks (3.1.3)
70
+ rspec-support (~> 3.1.0)
71
+ rspec-support (3.1.2)
72
+ ruby-progressbar (1.7.0)
73
+ rubyzip (1.1.6)
74
+ simplecov (0.9.1)
75
+ docile (~> 1.1.0)
76
+ multi_json (~> 1.0)
77
+ simplecov-html (~> 0.8.0)
78
+ simplecov-html (0.8.0)
79
+ slop (3.6.0)
80
+ sooth (1.0.0)
81
+ thread_safe (0.3.4)
82
+ yard (0.8.7.6)
83
+
84
+ PLATFORMS
85
+ ruby
86
+
87
+ DEPENDENCIES
88
+ bundler (~> 1.7)
89
+ byebug (~> 3.5)
90
+ cld (~> 0.7)
91
+ highline (~> 1.6)
92
+ hodel_3000_compliant_logger (~> 0.1)
93
+ jeweler (~> 2.0)
94
+ rdoc (~> 4.1)
95
+ rspec (~> 3.1)
96
+ ruby-progressbar (~> 1.7)
97
+ rubyzip (~> 1.1)
98
+ simplecov (~> 0.9)
99
+ sooth (~> 1.0)
100
+ yard (~> 0.8)
data/README.md ADDED
@@ -0,0 +1,187 @@
1
+ [![Gratipay](https://img.shields.io/gratipay/Kranzky.svg)](https://gratipay.com/Kranzky/)
2
+ [![Gem Version](https://badge.fury.io/rb/megahal.svg)](http://badge.fury.io/rb/megahal)
3
+ [![Dependency Status](https://gemnasium.com/jasonhutchens/megahal.png)](https://gemnasium.com/jasonhutchens/megahal)
4
+ [![Build Status](https://semaphoreapp.com/api/v1/projects/6889bf33-e547-4200-a4fb-66b339a83d82/307128/shields_badge.svg)](https://semaphoreapp.com/jasonhutchens/megahal)
5
+ [![Code Climate](https://codeclimate.com/github/jasonhutchens/megahal.png)](https://codeclimate.com/github/jasonhutchens/megahal)
6
+
7
+ MegaHAL
8
+ =======
9
+
10
+ MegaHAL is a learning chatterbot.
11
+
12
+ You can run it as a command-line application, or embed it in your own
13
+ application and make calls to it via a simple
14
+ [API](http://rubydoc.info/github/jasonhutchens/megahal/master/frames).
15
+
16
+ It is built on top of [Sooth](https://github.com/jasonhutchens/sooth), a simple
17
+ stochastic predictive model.
18
+
19
+ This new version of MegaHAL was written in homage of the original, which I wrote
20
+ around twenty years ago. As these things go, the Ruby version is a fraction of
21
+ the size of the [original C version](https://github.com/pteichman/megahal/blob/master/Megahal/megahal.c).
22
+
23
+ The oldest record I have of MegaHAL is a USENET post from April 30, 1995,
24
+ which is reproduced at the bottom of this README.
25
+
26
+ Getting Started
27
+ ---------------
28
+
29
+ Running the command-line version of MegaHAL is simple:
30
+
31
+ ```
32
+ > gem install megahal
33
+ > megahal
34
+ +----------------------------------------------------------+
35
+ | |
36
+ | # # ###### #### ## # # ## # |
37
+ | ## ## # # # # # # # # # # |
38
+ | # ## # ##### # # # ###### # # # |
39
+ | # # # # ### ###### # # ###### # |
40
+ | # # # # # # # # # # # # |
41
+ | # # ###### #### # # # # # # ###### |
42
+ | |
43
+ | Type "/help" for options and "/quit" to terminate. |
44
+ +----------------------------------------------------------+
45
+
46
+ Greetings and salutations to thee and thine.
47
+ >
48
+ ```
49
+
50
+ If you type `/help` at the prompt, you'll be presented with a menu:
51
+
52
+ ```
53
+ 1. cancel
54
+ 2. reset
55
+ 3. brain
56
+ 4. train
57
+ 5. load
58
+ 6. save
59
+ 7. ignore
60
+ 8. quit
61
+ ```
62
+
63
+ Make a selection by typing the number or the name of the menu item:
64
+
65
+ 1. `cancel`: go back without making a selection
66
+ 1. `reset`: clear MegaHAL's brain, restoring it to a blank slate
67
+ 1. `brain`: choose from a number of existing personalities (see below)
68
+ 1. `train`: give MegaHAL a plain text file to learn from
69
+ 1. `load`: load a previously saved brain from a file
70
+ 1. `save`: save the current MegaHAL brain to a file
71
+ 1. `ignore`: prevent MegaHAL from learning from user input; this is good if you want to chat without introducing changes to the brain
72
+ 1. `quit`: immediately exit MegaHAL, losing any unsaved changes
73
+
74
+ If you select the `brain` menu item above, you'll be presented with a list of
75
+ pre-existing MegaHAL brains to choose from:
76
+
77
+ 1. `cancel`: go back without making a selection
78
+ 2. `default`: the personality used for the 1998 Loebner competition
79
+ 3. `aliens`: Bishop from Aliens!
80
+ 4. `ferris`: Mr. Ferris Bueller himself! Bueller! Bueller!
81
+ 5. `pepys`: Samuel Pepys, taken from the @samuelpepys Twitter feed
82
+ 6. `pulp`: Marsellus Wallace from Pulp Fiction!
83
+ 7. `sherlock`: Sherlock Holmes, with quotes taken from all the books
84
+ 8. `startrek`: Data from Star Trek (thanks to mbaker)
85
+ 9. `starwars`: Threepio from the Star Wars Trilogy!
86
+
87
+ Example
88
+ -------
89
+
90
+ Here is an example conversation transcript, taken directly from the `megahal.log` file (which is written each time you interact with MegaHAL):
91
+
92
+ ```
93
+ (brain changed to sherlock holmes)
94
+ MH10: On the strange coincidences, the plannings, the cross-purposes, the wonderful chains of events, working through generations, and leading to the composition of a woman.
95
+ USER: Who are you?
96
+ MH10: You could never guess how I employed my morning, or what I ended by doing.
97
+ USER: Did you play a game?
98
+ MH10: Come, Watson, come! The game is afoot.
99
+ USER: How exciting!
100
+ MH10: Isn't it gorgeous! What do you think of it.
101
+ USER: I think it's great. What are we going to do?
102
+ MH10: I think, perhaps, it is simplicity itself.
103
+ USER: Tell me then.
104
+ MH10: Your statement is, I want you?
105
+ USER: Ummm... no.
106
+ MH10: Yes, certainly.
107
+ USER: I think you're confused.
108
+ MH10: I think that you have been too busy to think of it.
109
+ USER: Are you saying what I think you're saying?
110
+ MH10: You know how to look into it.
111
+ USER: So do you by the sound of it.
112
+ MH10: I have been of material assistance to me for fifty minutes.
113
+ USER: Is this non-stop double entendre?
114
+ MH10: More than that it is a great thing for me to be able to understand that I have ever listened.
115
+ USER: Let's go and do something. Or get a bite to eat.
116
+ MH10: That is interesting.
117
+ USER: Why?
118
+ MH10: Because there are fifty who can reason analytically.
119
+ USER: Name them.
120
+ MH10: My name is Sherlock Holmes.
121
+ USER: And who are the other forty-nine?
122
+ MH10: I want to ascertain.
123
+ USER: You mean that you don't know?
124
+ MH10: Light a cigar and let me see if I can do what you have told me I think that both inferences are permissible.
125
+ USER: Well, it's been interesting. I must leave.
126
+ MH10: No crime, but a very interesting statement.
127
+ USER: Goodbye.
128
+ MH10: You must get home instantly and act.
129
+ MegaHAL Stopped
130
+ ```
131
+
132
+ USENET Announcement from 1995
133
+ -----------------------------
134
+
135
+ ```
136
+ Have a weird conversation with a computer
137
+ -----------------------------------------
138
+
139
+ Recently I added a feature to my home page allowing the user to "talk" to a
140
+ computer program of mine. The program was not written very intelligently, so
141
+ most of the time its replies consisted of incoherent babble.
142
+
143
+ Version 2 came and went, and now version 3 - MegaHAL - is ready for release.
144
+ The new features of the program are:-
145
+
146
+ * A second-order markov model is used, and it is doubly-linked. This
147
+ means that the computers sentences tend to be more grammatical.
148
+ * Punctuation is supported, which segments the sentences realistically.
149
+ * The reply given by the computer is based upon one of the words in
150
+ the input string. The word selected is one that maximises the ratio
151
+ (number of times since word was last used)/(number of times word has
152
+ appeared).
153
+ * The computers reply is generated from this keyword, and may be up to
154
+ 100 words long. The reply is generated in such a way that it is
155
+ impossible to get stuck in infinite loops.
156
+ * The keyword used is highlighted in the reply.
157
+
158
+ Some example conversations are given below:-
159
+
160
+ USER: you are crazy
161
+ HAL: WE *ARE* WEIRD.
162
+
163
+ USER: What is the meaning of life oh wise one?
164
+ HAL: *LIFE* IS THE ROOM.
165
+
166
+ USER: this is not getting us very far
167
+ HAL: YES I AM *GETTING* BORED OF GLOBAL DOMINATION.
168
+
169
+ USER: I have no idea.
170
+ HAL: *NO* IT IS IN HEAVEN.
171
+ USER: Is it really?
172
+ HAL: YES *IT* IS.
173
+
174
+ USER: My name is Jason.
175
+ HAL: I THINK ALAN TURING WAS A GIRLIE, JUST LIKE *MY* DEAR MAMA
176
+
177
+ The last response was generated from a combination of a discussion
178
+ about Alan Turing, and Monty Python's Lumberjack Song. Surely this
179
+ must be a sign of intelligence ;^)
180
+
181
+ Have fun!
182
+ ```
183
+
184
+ Copyright
185
+ ---------
186
+
187
+ Copyright (c) 2014 Jason Hutchens. See UNLICENSE for further details.
data/Rakefile ADDED
@@ -0,0 +1,44 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "megahal"
18
+ gem.homepage = "http://github.com/jasonhutchens/megahal"
19
+ gem.license = "UNLICENSE"
20
+ gem.summary = %Q{MegaHAL is a learning chatterbot.}
21
+ gem.description = %Q{Have a weird conversation with a computer.}
22
+ gem.email = "jasonhutchens@gmail.com"
23
+ gem.authors = ["Jason Hutchens"]
24
+ gem.required_ruby_version = "~> 2.1"
25
+ # dependencies defined in Gemfile
26
+ end
27
+ Jeweler::RubygemsDotOrgTasks.new
28
+
29
+ require 'rspec/core'
30
+ require 'rspec/core/rake_task'
31
+ RSpec::Core::RakeTask.new(:spec) do |spec|
32
+ spec.pattern = FileList['spec/**/*_spec.rb']
33
+ end
34
+
35
+ desc "Code coverage detail"
36
+ task :simplecov do
37
+ ENV['COVERAGE'] = "true"
38
+ Rake::Task['spec'].execute
39
+ end
40
+
41
+ task :default => :spec
42
+
43
+ require 'yard'
44
+ YARD::Rake::YardocTask.new
data/UNLICENSE ADDED
@@ -0,0 +1,24 @@
1
+ This is free and unencumbered software released into the public domain.
2
+
3
+ Anyone is free to copy, modify, publish, use, compile, sell, or
4
+ distribute this software, either in source code form or as a compiled
5
+ binary, for any purpose, commercial or non-commercial, and by any
6
+ means.
7
+
8
+ In jurisdictions that recognize copyright laws, the author or authors
9
+ of this software dedicate any and all copyright interest in the
10
+ software to the public domain. We make this dedication for the benefit
11
+ of the public at large and to the detriment of our heirs and
12
+ successors. We intend this dedication to be an overt act of
13
+ relinquishment in perpetuity of all present and future rights to this
14
+ software under copyright law.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ For more information, please refer to <http://unlicense.org/>
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.4.0
data/bin/megahal ADDED
@@ -0,0 +1,196 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'megahal'
4
+ require 'highline/import'
5
+ require 'hodel_3000_compliant_logger'
6
+ require 'ruby-progressbar'
7
+
8
+ say("<%= color('" + <<-EOS + "', BOLD) %>")
9
+ +----------------------------------------------------------+
10
+ | |
11
+ | # # ###### #### ## # # ## # |
12
+ | ## ## # # # # # # # # # # |
13
+ | # ## # ##### # # # ###### # # # |
14
+ | # # # # ### ###### # # ###### # |
15
+ | # # # # # # # # # # # # |
16
+ | # # ###### #### # # # # # # ###### |
17
+ | |
18
+ | Type "/help" for options and "/quit" to terminate. |
19
+ +----------------------------------------------------------+
20
+ EOS
21
+
22
+ class MegaLog
23
+ def initialize
24
+ @logger = Hodel3000CompliantLogger.new("megahal.log")
25
+ @logger.info "MegaHAL Started"
26
+ end
27
+ def exit
28
+ @logger.info "MegaHAL Stopped"
29
+ end
30
+ def error(message)
31
+ @logger.error "(#{message})"
32
+ message = HighLine.color("(#{message})", :dark, :red)
33
+ say(message)
34
+ end
35
+ def status(message)
36
+ @logger.info "(#{message})"
37
+ message = HighLine.color("(#{message})", :dark, :yellow)
38
+ say(message)
39
+ end
40
+ def user(message)
41
+ @logger.info "USER: #{message}"
42
+ end
43
+ def puts(message)
44
+ @logger.info "MH10: #{message}"
45
+ message = HighLine.color(message, :bold, :green)
46
+ say(message)
47
+ end
48
+ end
49
+
50
+ log = MegaLog.new
51
+
52
+ def list_menu(megahal, log)
53
+ choose do |menu|
54
+ menu.prompt = "? "
55
+ menu.choice(:cancel) do
56
+ log.status('cancelled')
57
+ return
58
+ end
59
+ menu.choice(:default) do
60
+ megahal.become(:default)
61
+ log.status('brain changed to the original loebner prize version')
62
+ end
63
+ menu.choice(:aliens) do
64
+ megahal.become(:aliens)
65
+ log.status('brain changed to bishop from aliens')
66
+ end
67
+ menu.choice(:ferris) do
68
+ megahal.become(:ferris)
69
+ log.status('brain changed to ferris bueller')
70
+ end
71
+ menu.choice(:pepys) do
72
+ megahal.become(:pepys)
73
+ log.status('brain changed to samuel pepys')
74
+ end
75
+ menu.choice(:pulp) do
76
+ megahal.become(:pulp)
77
+ log.status('brain changed to marsellus wallace from pulp fiction')
78
+ end
79
+ menu.choice(:sherlock) do
80
+ megahal.become(:sherlock)
81
+ log.status('brain changed to sherlock holmes')
82
+ end
83
+ menu.choice(:startrek) do
84
+ megahal.become(:startrek)
85
+ log.status('brain changed to data from star trek')
86
+ end
87
+ menu.choice(:starwars) do
88
+ megahal.become(:starwars)
89
+ log.status('brain changed to threepio from star wars')
90
+ end
91
+ end
92
+ log.puts(megahal.reply(nil))
93
+ end
94
+
95
+ def help_menu(megahal, log)
96
+ choose do |menu|
97
+ menu.prompt = "? "
98
+ menu.choice(:cancel) do
99
+ log.status('cancelled')
100
+ return
101
+ end
102
+ menu.choice(:reset) do
103
+ megahal.clear
104
+ log.status('brain cleared')
105
+ end
106
+ menu.choice(:brain) do
107
+ log.status('show brain menu')
108
+ list_menu(megahal, log)
109
+ end
110
+ menu.choice(:train) do
111
+ log.status('train on a text file')
112
+ filename = ask("Filename: ")
113
+ unless File.exists?(filename)
114
+ log.error("no such file")
115
+ else
116
+ begin
117
+ bar = ProgressBar.create(title: "Training", total: nil)
118
+ megahal.train(filename, bar)
119
+ bar.finish
120
+ log.status("training succesfull for '#{filename}'")
121
+ log.puts(megahal.reply(nil))
122
+ rescue => e
123
+ log.error(e.message)
124
+ end
125
+ end
126
+ end
127
+ menu.choice(:load) do
128
+ log.status('load a brain file')
129
+ filename = ask("Filename: ")
130
+ unless File.exists?(filename)
131
+ log.error("no such file")
132
+ else
133
+ begin
134
+ bar = ProgressBar.create(title: "Loading", total: nil)
135
+ megahal.load(filename, bar)
136
+ bar.finish
137
+ log.status("loading succesfull for '#{filename}'")
138
+ log.puts(megahal.reply(nil))
139
+ rescue => e
140
+ log.error(e.message)
141
+ end
142
+ end
143
+ end
144
+ menu.choice(:save) do
145
+ log.status('save a brain file')
146
+ filename = ask("Filename: ")
147
+ if File.exists?(filename)
148
+ log.error("file already exists")
149
+ else
150
+ begin
151
+ bar = ProgressBar.create(title: "Saving", total: nil)
152
+ megahal.save(filename, bar)
153
+ bar.finish
154
+ log.status("saving succesfull for '#{filename}'")
155
+ rescue => e
156
+ log.error(e.message)
157
+ end
158
+ end
159
+ end
160
+ if megahal.learning
161
+ menu.choice(:ignore) do
162
+ megahal.learning = false
163
+ log.status('stop learning from user input')
164
+ end
165
+ else
166
+ menu.choice(:learn) do
167
+ megahal.learning = true
168
+ log.status('start learning from user input')
169
+ end
170
+ end
171
+ menu.choice(:quit) do
172
+ log.status('exiting')
173
+ exit
174
+ end
175
+ end
176
+ end
177
+
178
+ megahal = MegaHAL.new
179
+ log.puts(megahal.reply(nil))
180
+ begin
181
+ loop do
182
+ input = ask("> ").strip
183
+ log.user(input)
184
+ if input.downcase =~ /^[\/\\#@](help|menu|info|list|h|\?)$/
185
+ log.status('show help menu')
186
+ help_menu(megahal, log)
187
+ elsif input.downcase =~ /^[\/\\#@](quit|exit|q|x)$/
188
+ log.status('exiting')
189
+ exit
190
+ else
191
+ log.puts(megahal.reply(input))
192
+ end
193
+ end
194
+ ensure
195
+ log.exit
196
+ end