akiva 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +15 -0
- data/.rspec +2 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +80 -0
- data/Guardfile +11 -0
- data/LICENSE +9 -0
- data/README.md +131 -0
- data/Rakefile +5 -0
- data/akiva.gemspec +38 -0
- data/lib/akiva.rb +11 -0
- data/lib/akiva/brain.rb +47 -0
- data/lib/akiva/cli.rb +58 -0
- data/lib/akiva/core_brain/actions/get_answers_from_subjects_and_properties.rb +73 -0
- data/lib/akiva/core_brain/actions/preparators/compare_two_subjects_properties_from_comparison_adjective.rb +19 -0
- data/lib/akiva/core_brain/actions/preparators/extract_property_from_comparison_adjective.rb +10 -0
- data/lib/akiva/core_brain/actions/preparators/regroup_separated_subjects.rb +10 -0
- data/lib/akiva/core_brain/actions/preparators/sort_answers_by_units.rb +35 -0
- data/lib/akiva/core_brain/actions/template.rb +23 -0
- data/lib/akiva/core_brain/filters/get_answers_from_subjects_and_properties.rb +15 -0
- data/lib/akiva/core_brain/filters/template.rb +9 -0
- data/lib/akiva/core_brain/formatters/boolean_from_comparison.rb +17 -0
- data/lib/akiva/core_brain/formatters/list_all_answers.rb +28 -0
- data/lib/akiva/core_brain/formatters/template.rb +19 -0
- data/lib/akiva/core_brain/helpers/comparison_adjectives_to_properties.rb +151 -0
- data/lib/akiva/core_brain/helpers/misc.rb +28 -0
- data/lib/akiva/core_brain/helpers/units.rb +167 -0
- data/lib/akiva/core_brain/loader.rb +3 -0
- data/lib/akiva/question.rb +88 -0
- data/lib/akiva/version.rb +9 -0
- data/spec/lib/akiva/brain_spec.rb +89 -0
- data/spec/lib/akiva/core_brain/actions/get_answers_from_subjects_and_properties_spec.rb +77 -0
- data/spec/lib/akiva/core_brain/actions/preparators/compare_two_subjects_properties_from_comparison_adjective_spec.rb +22 -0
- data/spec/lib/akiva/core_brain/actions/preparators/extract_property_from_comparison_adjective_spec.rb +11 -0
- data/spec/lib/akiva/core_brain/actions/preparators/regroup_separated_subjects_spec.rb +11 -0
- data/spec/lib/akiva/core_brain/actions/preparators/sort_answers_by_units_spec.rb +36 -0
- data/spec/lib/akiva/core_brain/filters/get_answers_from_subjects_and_properties_spec.rb +44 -0
- data/spec/lib/akiva/core_brain/formatters/boolean_from_comparison_spec.rb +38 -0
- data/spec/lib/akiva/core_brain/formatters/list_all_answers_spec.rb +60 -0
- data/spec/lib/akiva/core_brain/helpers/misc_spec.rb +26 -0
- data/spec/lib/akiva/core_brain/helpers/units_spec.rb +141 -0
- data/spec/lib/akiva/core_brain/question_spec.rb +170 -0
- data/spec/spec_helper.rb +37 -0
- data/spec/support/akiva_brain_helpers.rb +13 -0
- data/spec/support/akiva_statements_helpers.rb +66 -0
- metadata +75 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3b141693c56778ea3c49884ce12a4c4d9eb9d029
|
4
|
+
data.tar.gz: ca1146e56d4efee470fe4f9b8d35302e51860fa1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ea210219041b617487364ceb0c6dc2578f1e2d1a13720f548158d9469cb5eab8a622c703034f7e02beecdf3257482c7a3a6b40919fc1ccd9fb7589d30d64a90e
|
7
|
+
data.tar.gz: 44c5775d503401d30be0bea714943da61ed0609a2bde759e767e80b80c073cee6119aa60712e35fa3beb914c2ce83effaca70a7241455bd4cd1adc5db70efabd
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
akiva (0.1.1)
|
5
|
+
awesome_print (~> 1.2)
|
6
|
+
rack (~> 1.4)
|
7
|
+
ruby-units (~> 1.4)
|
8
|
+
thebigdb (~> 1.3)
|
9
|
+
thor (~> 0.18)
|
10
|
+
|
11
|
+
GEM
|
12
|
+
remote: https://rubygems.org/
|
13
|
+
specs:
|
14
|
+
addressable (2.3.5)
|
15
|
+
awesome_print (1.2.0)
|
16
|
+
celluloid (0.15.2)
|
17
|
+
timers (~> 1.1.0)
|
18
|
+
coderay (1.1.0)
|
19
|
+
crack (0.4.1)
|
20
|
+
safe_yaml (~> 0.9.0)
|
21
|
+
diff-lcs (1.2.5)
|
22
|
+
ffi (1.9.3)
|
23
|
+
formatador (0.2.4)
|
24
|
+
guard (2.2.5)
|
25
|
+
formatador (>= 0.2.4)
|
26
|
+
listen (~> 2.1)
|
27
|
+
lumberjack (~> 1.0)
|
28
|
+
pry (>= 0.9.12)
|
29
|
+
thor (>= 0.18.1)
|
30
|
+
guard-rspec (2.6.0)
|
31
|
+
guard (>= 1.8)
|
32
|
+
rspec (~> 2.13)
|
33
|
+
listen (2.4.0)
|
34
|
+
celluloid (>= 0.15.2)
|
35
|
+
rb-fsevent (>= 0.9.3)
|
36
|
+
rb-inotify (>= 0.9)
|
37
|
+
lumberjack (1.0.4)
|
38
|
+
method_source (0.8.2)
|
39
|
+
pry (0.9.12.4)
|
40
|
+
coderay (~> 1.0)
|
41
|
+
method_source (~> 0.8)
|
42
|
+
slop (~> 3.4)
|
43
|
+
rack (1.5.2)
|
44
|
+
rake (10.1.1)
|
45
|
+
rb-fchange (0.0.6)
|
46
|
+
ffi
|
47
|
+
rb-fsevent (0.9.4)
|
48
|
+
rb-inotify (0.9.3)
|
49
|
+
ffi (>= 0.5.0)
|
50
|
+
rspec (2.14.1)
|
51
|
+
rspec-core (~> 2.14.0)
|
52
|
+
rspec-expectations (~> 2.14.0)
|
53
|
+
rspec-mocks (~> 2.14.0)
|
54
|
+
rspec-core (2.14.7)
|
55
|
+
rspec-expectations (2.14.4)
|
56
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
57
|
+
rspec-mocks (2.14.4)
|
58
|
+
ruby-units (1.4.4)
|
59
|
+
safe_yaml (0.9.7)
|
60
|
+
slop (3.4.7)
|
61
|
+
thebigdb (1.4.1)
|
62
|
+
rack (~> 1.4)
|
63
|
+
thor (0.18.1)
|
64
|
+
timers (1.1.0)
|
65
|
+
webmock (1.16.1)
|
66
|
+
addressable (>= 2.2.7)
|
67
|
+
crack (>= 0.3.2)
|
68
|
+
|
69
|
+
PLATFORMS
|
70
|
+
ruby
|
71
|
+
|
72
|
+
DEPENDENCIES
|
73
|
+
akiva!
|
74
|
+
guard-rspec (~> 2.3)
|
75
|
+
rake (~> 10.0)
|
76
|
+
rb-fchange (~> 0)
|
77
|
+
rb-fsevent (~> 0)
|
78
|
+
rb-inotify (~> 0)
|
79
|
+
rspec (~> 2.12)
|
80
|
+
webmock (~> 1.9)
|
data/Guardfile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
guard :rspec do
|
2
|
+
watch("spec/spec_helper.rb") { "spec" }
|
3
|
+
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
|
4
|
+
watch("lib/akiva/question.rb") { "spec" }
|
5
|
+
|
6
|
+
watch(%r{^spec/.+_spec\.rb$})
|
7
|
+
watch(%r{^lib/akiva\.rb$}) { "spec" }
|
8
|
+
watch(%r{^lib/akiva/(.+)\.rb$}) do |m|
|
9
|
+
"spec/lib/akiva/#{m[1]}_spec.rb"
|
10
|
+
end
|
11
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2014, Christophe Maximin <christophe@thebigdb.com>
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
6
|
+
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
8
|
+
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
Akiva
|
2
|
+
=====
|
3
|
+
|
4
|
+
Akiva is a simple natural-language-processing, question-answering, artificial intelligence.
|
5
|
+
|
6
|
+
Its main role is to take a question, deconstruct it in order to query the
|
7
|
+
collaborative database of facts [TheBigDB](http://thebigdb.com), and format the answer into something readable for a human.
|
8
|
+
|
9
|
+
Akiva is obviously at a very early stage, and your contributions are more than welcome! See the "Contributing" section below for more info.
|
10
|
+
|
11
|
+
## Why?
|
12
|
+
|
13
|
+
> ** What's the point? Isn't Google's Knowledge graph enough? What about Wolfram|Alpha? **
|
14
|
+
> -- you, right now
|
15
|
+
|
16
|
+
STORY TIME!
|
17
|
+
Back in 2005, while bored to death in a college class and daydreaming about how knowledge is structured, I asked myself why there wasn't anywhere I could ask questions in natural language. Because it would be pretty cool if there was.
|
18
|
+
I went back home, prototyped a little program doing just that. It sucked but it kinda worked, so I thought *"well, it isn't that hard, I guess geniuses everywhere are working on that, no need for me to spend more time on it. It surely will be available to everyone soon enough!"*. **Three years** passed: nothing.
|
19
|
+
The year 2009 saw the release of Wolfram|Alpha, which pretty much blew my mind: it was almost perfect. I guessed I just needed to wait a few more years and I can have all my trivial questions answered.
|
20
|
+
Fast forward **five more years**, and I'm sad to see this (as of January 6th, 2014):
|
21
|
+
|
22
|
+
[Google](http://imgur.com/RWjgcoM), [Wolfram|Apha](http://imgur.com/4QOHcN1), [Yahoo!](http://imgur.com/KXYnoqA) and [Bing](http://imgur.com/oOTloSQ) fail to answer the simple question « Is the iPhone 5s heavier than the Galaxy S4? » (click their names to see the results given);
|
23
|
+
Akiva answers "**No (iPhone 5s => 112 grams; Galaxy S4 => 130 grams)**". With only a few lines of code.
|
24
|
+
|
25
|
+
With the same few lines, Akiva can accurately smartly all the following questions:
|
26
|
+
|
27
|
+
* « What are the weight, width and height of an iPhone 5s and a Galaxy S4 ? »
|
28
|
+
* « What is the height requirement for Space Mountain ? »
|
29
|
+
|
30
|
+
… and much more.
|
31
|
+
|
32
|
+
|
33
|
+
**TL;DR: I truly love Google's Knowledge graph; I'm an eternal fan of Wolfram|Alpha, but I'm tired of waiting for search engines to implement a fully working simple question-answering engine.
|
34
|
+
Still, Akiva is not trying to be a real "*computational* knowledge engine" so it is NOT competing at all with Wolfram|Alpha.**
|
35
|
+
|
36
|
+
## « It's nothing new!!! »
|
37
|
+
|
38
|
+
Maybe. What I, and you probably will, like about Akiva, is the fact that is always improving from two different angles:
|
39
|
+
|
40
|
+
* Akiva is open-source and a free software, so it can answer more and more types of questions with time
|
41
|
+
* Akiva's data source is the collaborative [TheBigDB](http://thebigdb.com), which makes it more knowledgable everyday
|
42
|
+
|
43
|
+
## Usage
|
44
|
+
|
45
|
+
gem install akiva
|
46
|
+
|
47
|
+
You can then ask a question like this:
|
48
|
+
|
49
|
+
$ akiva ask "What's the weight of an iPhone 5s ?"
|
50
|
+
|
51
|
+
# Will output something like:
|
52
|
+
# 112 grams
|
53
|
+
|
54
|
+
Or you can ask a more complex question, like this one:
|
55
|
+
|
56
|
+
$ akiva ask "What are the weight, width and height of an iPhone 5s, a Nexus 5 and a Galaxy S4 ?"
|
57
|
+
|
58
|
+
# Will output something like:
|
59
|
+
# iPhone 5s => Weight: 112 grams, Width: 58.6 mm, Height: 123.8 mm
|
60
|
+
# Nexus 5 => Weight: 130 grams, Width: 69.17 mm, Height: 137.84 mm
|
61
|
+
# Galaxy S4 => Weight: 130 grams, Width: 58.6 mm, Height: 136.6 mm
|
62
|
+
|
63
|
+
In order to integrate it within an existing app, you can do something like this:
|
64
|
+
|
65
|
+
require "akiva"
|
66
|
+
puts Akiva::Question.new("What are the weight, width and height of an iPhone 5s, a Nexus 5 and a Galaxy S4 ?").formatted_response
|
67
|
+
|
68
|
+
Tip: If you're thinking about caching the requests made to TheBigDB, you should probably check out [the section "Caching" on its github page](https://github.com/thebigdb/thebigdb-ruby#caching).
|
69
|
+
|
70
|
+
## Expanding
|
71
|
+
|
72
|
+
Akiva is quite easily expandable. Take for example this completely useless example, where Akiva would tell you what's the first word out of a list you provided.
|
73
|
+
|
74
|
+
require "akiva"
|
75
|
+
|
76
|
+
Akiva::Brain.update do
|
77
|
+
add_filter :get_first_word, /\AWhat's the first word of (?<words>.+?)\??\Z/i, formatter: :display_expected_word
|
78
|
+
|
79
|
+
add_action :get_first_word do |response|
|
80
|
+
response[:first_word] = response[:filter_captures]["words"].split(/ /).first
|
81
|
+
end
|
82
|
+
|
83
|
+
add_formatter :display_expected_word do |response|
|
84
|
+
response[:formatted] = "The word you're looking for is: « #{response[:first_word]} »"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# execution looks like:
|
89
|
+
# Akiva::Question.new("What's the first word of love is stronger than hate?").formatted_response
|
90
|
+
# => "The word you're looking for is: « love »"
|
91
|
+
|
92
|
+
For more info, you'll probably want to take a look at the templates for filters in [lib/akiva/core_brain/filters/template.rb](https://github.com/thebigdb/akiva/blob/master/lib/akiva/core_brain/filters/template.rb), actions in [lib/akiva/core_brain/actions/template.rb](https://github.com/thebigdb/akiva/blob/master/lib/akiva/core_brain/actions/template.rb) and formatters in [lib/akiva/core_brain/formatters/template.rb](https://github.com/thebigdb/akiva/blob/master/lib/akiva/core_brain/formatters/template.rb).
|
93
|
+
Also, don't hesitate to look around, see how existing filters/actions/formatters are built.
|
94
|
+
|
95
|
+
|
96
|
+
## Contributing
|
97
|
+
|
98
|
+
You can run the tests with:
|
99
|
+
|
100
|
+
$ bundle install
|
101
|
+
$ bundle exec rspec spec/
|
102
|
+
|
103
|
+
As you can see, there are lots of types of questions Akiva can't answer yet (see [spec/lib/akiva/core_brain/question_spec.rb](https://github.com/thebigdb/akiva/blob/master/spec/lib/akiva/core_brain/question_spec.rb)). Just take one of them and make it work!
|
104
|
+
|
105
|
+
There are no crazy rules to contribute, just write good code, good tests, and send a pull request. It will really appreciated!
|
106
|
+
|
107
|
+
## List of question types currently understood
|
108
|
+
|
109
|
+
This is a non-exhaustive list of question types Akiva can answer. Just remember that the fact that Akiva actually has the data to answer the question is entirely dependent on what is available in TheBigDB.
|
110
|
+
The words in parenthesis are variable.
|
111
|
+
|
112
|
+
What's (the weight) of (an iPhone 5s) ?
|
113
|
+
>>> 112 grams
|
114
|
+
|
115
|
+
What are (the weight and height) of (an iPhone 5s) ?
|
116
|
+
>>> Weight: 112 grams, Height: 123.8 mm
|
117
|
+
|
118
|
+
What are (the weight) of (an iPhone 5s and a Galaxy S4) ?
|
119
|
+
>>> iPhone 5s => 112 grams; Galaxy S4 => 130 grams
|
120
|
+
|
121
|
+
What are (the weight and height) of (an iPhone 5s and a Galaxy S4) ?
|
122
|
+
>>> iPhone 5s => Weight: 112 grams, Height: 123.8 mm
|
123
|
+
Galaxy S4 => Weight: 130 grams, Height: 136.6 mm
|
124
|
+
|
125
|
+
Is (the iPhone 5s) (heavier) than (the Galaxy S4) ?
|
126
|
+
>>> No (iPhone 5s => 112 grams; Galaxy S4 => 130 grams)
|
127
|
+
|
128
|
+
|
129
|
+
## License
|
130
|
+
|
131
|
+
This software is distributed under the MIT License. Copyright (c) 2014, Christophe Maximin <christophe@thebigdb.com>
|
data/Rakefile
ADDED
data/akiva.gemspec
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
$:.push File.expand_path("../lib", __FILE__)
|
2
|
+
require "akiva/version"
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "akiva"
|
6
|
+
s.version = Akiva::VERSION::STRING
|
7
|
+
s.summary = "Simple natural language processing, question-answering artificial intelligence, based on TheBigDB"
|
8
|
+
s.description = "Akiva is a simple natural language processing, question-answering artificial intelligence. It is a demonstration of how to use the API of TheBigDB (http://thebigbdb.com) to create knowledgable software."
|
9
|
+
s.authors = ["Christophe Maximin"]
|
10
|
+
s.email = "christophe@thebigdb.com"
|
11
|
+
s.homepage = "https://github.com/thebigdb/akiva"
|
12
|
+
s.licenses = ['MIT']
|
13
|
+
|
14
|
+
s.platform = Gem::Platform::RUBY
|
15
|
+
|
16
|
+
s.add_runtime_dependency "rack", "~> 1.4"
|
17
|
+
s.add_runtime_dependency "ruby-units", "~> 1.4"
|
18
|
+
s.add_runtime_dependency "thebigdb", "~> 1.3"
|
19
|
+
s.add_runtime_dependency "thor", "~> 0.18"
|
20
|
+
# s.add_runtime_dependency "numbers_in_words", "~> 0.0", ">= 0.0.1"
|
21
|
+
s.add_runtime_dependency "awesome_print", "~> 1.2"
|
22
|
+
|
23
|
+
s.add_development_dependency "rake", "~> 10.0"
|
24
|
+
s.add_development_dependency "rspec", "~> 2.12"
|
25
|
+
s.add_development_dependency "guard-rspec", "~> 2.3"
|
26
|
+
s.add_development_dependency "rb-inotify", "~> 0"
|
27
|
+
s.add_development_dependency "rb-fsevent", "~> 0"
|
28
|
+
s.add_development_dependency "rb-fchange", "~> 0"
|
29
|
+
s.add_development_dependency "webmock", "~> 1.9"
|
30
|
+
|
31
|
+
|
32
|
+
|
33
|
+
s.files = `git ls-files`.split("\n")
|
34
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
35
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
36
|
+
|
37
|
+
s.require_paths = ["lib"]
|
38
|
+
end
|
data/lib/akiva.rb
ADDED
data/lib/akiva/brain.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
module Akiva
|
2
|
+
module Brain
|
3
|
+
@@filters = []
|
4
|
+
@@actions = {}
|
5
|
+
@@formatters = {}
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def update(&block)
|
9
|
+
instance_exec(&block)
|
10
|
+
end
|
11
|
+
|
12
|
+
def empty
|
13
|
+
@@filters = []
|
14
|
+
@@actions = {}
|
15
|
+
@@formatters = {}
|
16
|
+
end
|
17
|
+
|
18
|
+
def add_filter(action_name, regex, options = {})
|
19
|
+
@@filters.unshift({
|
20
|
+
regex: regex,
|
21
|
+
action: action_name
|
22
|
+
}.merge(options))
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_action(action_name, class_instance = nil, &block)
|
26
|
+
@@actions[action_name] = class_instance || block
|
27
|
+
end
|
28
|
+
|
29
|
+
def add_formatter(formatter_name, class_instance = nil, &block)
|
30
|
+
@@formatters[formatter_name] = class_instance || block
|
31
|
+
end
|
32
|
+
|
33
|
+
# readers
|
34
|
+
def filters
|
35
|
+
@@filters
|
36
|
+
end
|
37
|
+
|
38
|
+
def actions
|
39
|
+
@@actions
|
40
|
+
end
|
41
|
+
|
42
|
+
def formatters
|
43
|
+
@@formatters
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/akiva/cli.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require "thor"
|
2
|
+
|
3
|
+
module Akiva
|
4
|
+
class CLI < Thor
|
5
|
+
|
6
|
+
desc "ask QUESTION", "Process a question, and display the answer"
|
7
|
+
# method_option "verbose", type: :boolean, aliases: "-v", desc: "Displays the elements found in the question"
|
8
|
+
# option :verbose, type: :boolean, aliases: "-v"
|
9
|
+
option "verbose", type: :boolean, aliases: "-v", desc: "Displays the requests made to TheBigDB"
|
10
|
+
option "headers", type: :boolean, desc: "Displays headers of the requests made to TheBigDB (depends on --verbose/-v)", default: false
|
11
|
+
option "caller", type: :boolean, desc: "Displays stack trace from which each request made to TheBigDB is made (depends on --verbose/-v)", default: false
|
12
|
+
option "api-host", type: :string, desc: "Host to send requests for TheBigDB", default: "api.thebigdb.com"
|
13
|
+
|
14
|
+
def ask(question)
|
15
|
+
TheBigDB.raise_on_api_status_error = true
|
16
|
+
|
17
|
+
TheBigDB.api_host = options["api-host"]
|
18
|
+
|
19
|
+
if options["verbose"]
|
20
|
+
require "awesome_print"
|
21
|
+
TheBigDB.before_request_execution = lambda do |request|
|
22
|
+
puts "REQUEST DATA SENT:"
|
23
|
+
data_sent = request.data_sent
|
24
|
+
data_sent.delete("headers") unless options["headers"]
|
25
|
+
ap data_sent
|
26
|
+
if options["caller"]
|
27
|
+
puts "CALLED FROM:"
|
28
|
+
puts caller.join("\n")
|
29
|
+
end
|
30
|
+
puts
|
31
|
+
end
|
32
|
+
|
33
|
+
TheBigDB.after_request_execution = lambda do |request|
|
34
|
+
puts "REQUEST DATA RECEIVED:"
|
35
|
+
data_received = request.data_received
|
36
|
+
data_received.delete("headers") unless options["headers"]
|
37
|
+
ap data_received
|
38
|
+
puts
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
akiva_question = Akiva::Question.new(question)
|
43
|
+
begin
|
44
|
+
if response = akiva_question.formatted_response
|
45
|
+
puts response.gsub("; ", "\n")
|
46
|
+
else
|
47
|
+
puts "Sorry, Akiva can't answer that question for now."
|
48
|
+
end
|
49
|
+
rescue TheBigDB::Request::ApiStatusError
|
50
|
+
puts "Sorry, it looks like TheBigDB is currently unavailable."
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
Akiva::CLI.start
|
@@ -0,0 +1,73 @@
|
|
1
|
+
Akiva::Brain.update do
|
2
|
+
|
3
|
+
add_action :get_answers_from_subjects_and_properties do |response|
|
4
|
+
|
5
|
+
# It's possible we're arriving here with already defined subjects and properties, in that case, skip the default request
|
6
|
+
unless response[:defined_subjects] and response[:defined_properties]
|
7
|
+
regex_matched_subjects = response[:filter_captures]["subjects"]
|
8
|
+
regex_matched_properties = response[:filter_captures]["properties"]
|
9
|
+
|
10
|
+
# First, we try the obvious subject x property, works if there's only one subject and one property
|
11
|
+
search = TheBigDB.search(subject: regex_matched_subjects, property: regex_matched_properties).with(per_page: 1)
|
12
|
+
|
13
|
+
if search["total_results"] == 1
|
14
|
+
statement = search["statements"].first
|
15
|
+
response[:subjects] = [statement["nodes"]["subject"]]
|
16
|
+
response[:properties] = {statement["nodes"]["subject"] => [statement["nodes"]["property"]]}
|
17
|
+
response[:answers] = {statement["nodes"]["subject"] => {statement["nodes"]["property"] => statement["nodes"]["answer"]}}
|
18
|
+
|
19
|
+
next # we're happy with what we have, no need to continue the action.
|
20
|
+
end
|
21
|
+
|
22
|
+
# If we don't have an obvious answer, it may be because we're searching for multiple subjects and/or properties
|
23
|
+
degrouped_subjects = Akiva::Brain::Helpers.degroup_multiple_values(regex_matched_subjects)
|
24
|
+
degrouped_properties = Akiva::Brain::Helpers.degroup_multiple_values(regex_matched_properties)
|
25
|
+
|
26
|
+
if degrouped_subjects.size == 1 and degrouped_properties.size == 1
|
27
|
+
next # sadly we don't have anything to further analyze/search for, so we're exiting the action empty-handed.
|
28
|
+
end
|
29
|
+
|
30
|
+
# Let's make products of elements to be sure we're not missing anything
|
31
|
+
products_mega_groups = []
|
32
|
+
products_mega_groups << [regex_matched_subjects].product(degrouped_properties)
|
33
|
+
products_mega_groups << degrouped_subjects.product([regex_matched_properties])
|
34
|
+
products_mega_groups << degrouped_subjects.product(degrouped_properties)
|
35
|
+
products_mega_groups.uniq!
|
36
|
+
else
|
37
|
+
products_mega_groups = [response[:defined_subjects].product(response[:defined_properties])]
|
38
|
+
end
|
39
|
+
|
40
|
+
products_mega_groups.each do |product_mega_group|
|
41
|
+
statements_compiled = {}
|
42
|
+
statements_found = 0
|
43
|
+
|
44
|
+
product_mega_group.each do |group|
|
45
|
+
search = TheBigDB.search(subject: group[0], property: group[1]).with(per_page: 1)
|
46
|
+
if search["total_results"] == 1
|
47
|
+
statements_found += 1
|
48
|
+
statement = search["statements"].first
|
49
|
+
statements_compiled[group[0]] ||= {}
|
50
|
+
statements_compiled[group[0]][group[1]] = statement["nodes"]["answer"]
|
51
|
+
else
|
52
|
+
break # if one is missing, we exit this each block since we're looking for a perfect product results
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
if statements_found == product_mega_group.size
|
57
|
+
response[:subjects] = statements_compiled.keys
|
58
|
+
response[:properties] = {}
|
59
|
+
statements_compiled.each_pair do |k, v|
|
60
|
+
response[:properties][k] = v.keys
|
61
|
+
end
|
62
|
+
response[:answers] = statements_compiled
|
63
|
+
|
64
|
+
break # we're happy with what we have, no need to continue mega_groups each-block.
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|