api_ai_wrapper 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +50 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +48 -0
- data/LICENSE +21 -0
- data/README.md +2 -0
- data/api_ai_wrapper.gemspec +14 -0
- data/lib/api_ai_wrapper.rb +10 -0
- data/lib/api_ai_wrapper/components/component.rb +35 -0
- data/lib/api_ai_wrapper/components/extractor_component.rb +16 -0
- data/lib/api_ai_wrapper/components/trainer_component.rb +16 -0
- data/lib/api_ai_wrapper/constants.rb +10 -0
- data/lib/api_ai_wrapper/engine.rb +40 -0
- data/lib/api_ai_wrapper/errors.rb +31 -0
- data/lib/api_ai_wrapper/extensions/hash.rb +37 -0
- data/lib/api_ai_wrapper/extensions/object.rb +13 -0
- data/lib/api_ai_wrapper/extensions/string.rb +21 -0
- data/lib/api_ai_wrapper/meaning_extractor.rb +28 -0
- data/lib/api_ai_wrapper/trainers/entity_trainer.rb +83 -0
- data/lib/api_ai_wrapper/trainers/intent_trainer.rb +72 -0
- data/spec/api_ai_wrapper/components/component_spec.rb +80 -0
- data/spec/api_ai_wrapper/components/extractor_component_spec.rb +38 -0
- data/spec/api_ai_wrapper/components/trainer_component_spec.rb +38 -0
- data/spec/api_ai_wrapper/engine_spec.rb +86 -0
- data/spec/api_ai_wrapper/meaning_extractor_spec.rb +30 -0
- data/spec/api_ai_wrapper/trainers/entity_trainer_spec.rb +98 -0
- data/spec/api_ai_wrapper/trainers/intent_trainer_spec.rb +65 -0
- data/spec/spec_helper.rb +111 -0
- metadata +92 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 469724d657925c38ac67bf0c138f213735ed032a
|
4
|
+
data.tar.gz: ccc0bd55f2401a5a57766bb53fd030076a528b52
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3b58704d1d01e1e063e562d349d6dd2379256d52f192c5298616ff0f6a98bb2ca5644beff1fc184abc3bab00ac28c67acd4064f93de4b9c0969f8135fce5891f
|
7
|
+
data.tar.gz: a941104c2cb448f049048fe366877863efff846252b3523b62a06b4c9e28e8f085b924872dddaabfe7d603f8781153f44cae6c356a72286d192477ff0c6e9771
|
data/.gitignore
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/spec/examples.txt
|
9
|
+
/test/tmp/
|
10
|
+
/test/version_tmp/
|
11
|
+
/tmp/
|
12
|
+
|
13
|
+
# Used by dotenv library to load environment variables.
|
14
|
+
# .env
|
15
|
+
|
16
|
+
## Specific to RubyMotion:
|
17
|
+
.dat*
|
18
|
+
.repl_history
|
19
|
+
build/
|
20
|
+
*.bridgesupport
|
21
|
+
build-iPhoneOS/
|
22
|
+
build-iPhoneSimulator/
|
23
|
+
|
24
|
+
## Specific to RubyMotion (use of CocoaPods):
|
25
|
+
#
|
26
|
+
# We recommend against adding the Pods directory to your .gitignore. However
|
27
|
+
# you should judge for yourself, the pros and cons are mentioned at:
|
28
|
+
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
29
|
+
#
|
30
|
+
# vendor/Pods/
|
31
|
+
|
32
|
+
## Documentation cache and generated files:
|
33
|
+
/.yardoc/
|
34
|
+
/_yardoc/
|
35
|
+
/doc/
|
36
|
+
/rdoc/
|
37
|
+
|
38
|
+
## Environment normalization:
|
39
|
+
/.bundle/
|
40
|
+
/vendor/bundle
|
41
|
+
/lib/bundler/man/
|
42
|
+
|
43
|
+
# for a library or gem, you might want to ignore these files since the code is
|
44
|
+
# intended to run in multiple environments; otherwise, check them in:
|
45
|
+
# Gemfile.lock
|
46
|
+
# .ruby-version
|
47
|
+
# .ruby-gemset
|
48
|
+
|
49
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
50
|
+
.rvmrc
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
addressable (2.5.1)
|
5
|
+
public_suffix (~> 2.0, >= 2.0.2)
|
6
|
+
crack (0.4.3)
|
7
|
+
safe_yaml (~> 1.0.0)
|
8
|
+
diff-lcs (1.3)
|
9
|
+
docile (1.1.5)
|
10
|
+
hashdiff (0.3.4)
|
11
|
+
httpclient (2.8.3)
|
12
|
+
json (2.1.0)
|
13
|
+
public_suffix (2.0.5)
|
14
|
+
rspec (3.6.0)
|
15
|
+
rspec-core (~> 3.6.0)
|
16
|
+
rspec-expectations (~> 3.6.0)
|
17
|
+
rspec-mocks (~> 3.6.0)
|
18
|
+
rspec-core (3.6.0)
|
19
|
+
rspec-support (~> 3.6.0)
|
20
|
+
rspec-expectations (3.6.0)
|
21
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
22
|
+
rspec-support (~> 3.6.0)
|
23
|
+
rspec-mocks (3.6.0)
|
24
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
25
|
+
rspec-support (~> 3.6.0)
|
26
|
+
rspec-support (3.6.0)
|
27
|
+
safe_yaml (1.0.4)
|
28
|
+
simplecov (0.14.1)
|
29
|
+
docile (~> 1.1.0)
|
30
|
+
json (>= 1.8, < 3)
|
31
|
+
simplecov-html (~> 0.10.0)
|
32
|
+
simplecov-html (0.10.1)
|
33
|
+
webmock (3.0.1)
|
34
|
+
addressable (>= 2.3.6)
|
35
|
+
crack (>= 0.3.2)
|
36
|
+
hashdiff
|
37
|
+
|
38
|
+
PLATFORMS
|
39
|
+
ruby
|
40
|
+
|
41
|
+
DEPENDENCIES
|
42
|
+
httpclient
|
43
|
+
rspec
|
44
|
+
simplecov
|
45
|
+
webmock
|
46
|
+
|
47
|
+
BUNDLED WITH
|
48
|
+
1.15.3
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2017
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'api_ai_wrapper'
|
3
|
+
s.version = '1.0.0'
|
4
|
+
s.date = '2017-08-04'
|
5
|
+
s.summary = "An API.AI Ruby Wrapper"
|
6
|
+
s.description = "A simple ruby library that let's any developer automate the training process of a Natural Language Processing Engine on API.AI, and retrieve meaning from new utterances."
|
7
|
+
s.authors = ["Vincent Gabou"]
|
8
|
+
s.email = 'vincent.gabou@gmail.com'
|
9
|
+
s.files = `git ls-files`.split($/)
|
10
|
+
s.homepage = 'http://rubygems.org/gems/api_ai_wrapper'
|
11
|
+
s.license = 'MIT'
|
12
|
+
|
13
|
+
s.add_runtime_dependency 'httpclient', '~> 2.8', '>= 2.8.0'
|
14
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require "json"
|
2
|
+
require "httpclient"
|
3
|
+
require "securerandom"
|
4
|
+
|
5
|
+
require "api_ai_wrapper/extensions/object"
|
6
|
+
require "api_ai_wrapper/extensions/string"
|
7
|
+
require "api_ai_wrapper/extensions/hash"
|
8
|
+
require "api_ai_wrapper/constants"
|
9
|
+
require "api_ai_wrapper/errors"
|
10
|
+
require "api_ai_wrapper/engine"
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module ApiAiWrapper::Components
|
2
|
+
|
3
|
+
class Component
|
4
|
+
attr_accessor :engine
|
5
|
+
|
6
|
+
# We define http_verb methods get/post/put/delete to add correct headers and parse result automatically
|
7
|
+
[:get, :post, :put, :delete].each do |http_verb|
|
8
|
+
define_method(http_verb.to_sym) do |url, params = {}|
|
9
|
+
raise_if_unauthorized # checks if the correct token is present
|
10
|
+
set_headers # sets headers with the correct token
|
11
|
+
|
12
|
+
response = self.engine.client.send(http_verb, url, params, self.engine.headers)
|
13
|
+
|
14
|
+
handle_response(JSON.parse(response.body))
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
# Throws an error if the call is not successful
|
21
|
+
# Returns response if no error is returned
|
22
|
+
def handle_response(response_body)
|
23
|
+
response = response_body.deep_symbolize_keys
|
24
|
+
response_status = response[:status]
|
25
|
+
response_code = response_status[:code]
|
26
|
+
|
27
|
+
if response_code != 200
|
28
|
+
raise ApiAiWrapper::Errors::Engine::ApiError.new(response_status[:errorDetails], response_code, response_status[:errorType])
|
29
|
+
end
|
30
|
+
|
31
|
+
response
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module ApiAiWrapper::Components
|
2
|
+
class ExtractorComponent < ApiAiWrapper::Components::Component
|
3
|
+
|
4
|
+
def raise_if_unauthorized
|
5
|
+
raise ApiAiWrapper::Errors::Engine::MissingToken.new("client token is missing") if self.engine.client_token.blank?
|
6
|
+
end
|
7
|
+
|
8
|
+
def set_headers
|
9
|
+
self.engine.headers = {
|
10
|
+
"Authorization" => "Bearer #{self.engine.client_token}",
|
11
|
+
"Content-Type" => "application/json; charset=utf-8"
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module ApiAiWrapper::Components
|
2
|
+
class TrainerComponent < ApiAiWrapper::Components::Component
|
3
|
+
|
4
|
+
def raise_if_unauthorized
|
5
|
+
raise ApiAiWrapper::Errors::Engine::MissingToken.new("developer token is missing") if self.engine.developer_token.blank?
|
6
|
+
end
|
7
|
+
|
8
|
+
def set_headers
|
9
|
+
self.engine.headers = {
|
10
|
+
"Authorization" => "Bearer #{self.engine.developer_token}",
|
11
|
+
"Content-Type" => "application/json; charset=utf-8"
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require "api_ai_wrapper/components/component"
|
2
|
+
require "api_ai_wrapper/components/trainer_component"
|
3
|
+
require "api_ai_wrapper/components/extractor_component"
|
4
|
+
require "api_ai_wrapper/trainers/intent_trainer"
|
5
|
+
require "api_ai_wrapper/trainers/entity_trainer"
|
6
|
+
require "api_ai_wrapper/meaning_extractor"
|
7
|
+
|
8
|
+
module ApiAiWrapper
|
9
|
+
class Engine
|
10
|
+
AUTOLOAD_CLASSES = [
|
11
|
+
ApiAiWrapper::Trainers::EntityTrainer,
|
12
|
+
ApiAiWrapper::Trainers::IntentTrainer,
|
13
|
+
ApiAiWrapper::MeaningExtractor
|
14
|
+
]
|
15
|
+
|
16
|
+
attr_accessor :client, :client_timeout, :headers, :locale, :base_url, :version, :client_token, :developer_token
|
17
|
+
attr_accessor :entity_trainer, :intent_trainer, :meaning_extractor
|
18
|
+
|
19
|
+
def initialize(options = {})
|
20
|
+
self.client = HTTPClient.new
|
21
|
+
self.client.receive_timeout = options[:client_timeout].presence || ApiAiWrapper::Constants::DEFAULT_CLIENT_TIMEOUT
|
22
|
+
self.locale = options[:locale].presence || ApiAiWrapper::Constants::DEFAULT_LOCALE
|
23
|
+
self.base_url = ApiAiWrapper::Constants::DEFAULT_BASE_URL
|
24
|
+
self.version = options[:version].presence || ApiAiWrapper::Constants::DEFAULT_VERSION
|
25
|
+
self.client_token = options[:client_token].presence
|
26
|
+
self.developer_token = options[:developer_token].presence
|
27
|
+
|
28
|
+
# RAISE ERROR IF NO TOKEN PRESENT
|
29
|
+
raise ApiAiWrapper::Errors::Engine::MissingTokens.new if self.client_token.blank? && self.developer_token.blank?
|
30
|
+
|
31
|
+
# define entity_trainer and intent_trainer on the fly
|
32
|
+
AUTOLOAD_CLASSES.each{ |class_name|
|
33
|
+
instance = class_name.new
|
34
|
+
instance.engine = self
|
35
|
+
self.send("#{class_name.to_s.demodulize.underscore}=", instance)
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class ApiAiWrapper::Errors
|
2
|
+
|
3
|
+
module Request
|
4
|
+
class UnsupportedParams < StandardError; end
|
5
|
+
end
|
6
|
+
|
7
|
+
module Engine
|
8
|
+
class MissingTokens < StandardError
|
9
|
+
def initialize(_message = "You have not set a developer or client token for this engine")
|
10
|
+
@message = _message
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class MissingToken < StandardError
|
15
|
+
def initialize(_message)
|
16
|
+
@message = "Unauthorized call - #{_message}"
|
17
|
+
@code = 401
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class ApiError < StandardError
|
22
|
+
def initialize(_message, _code, _status)
|
23
|
+
@message = _message
|
24
|
+
@code = _code
|
25
|
+
@status = _status
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class Hash
|
2
|
+
|
3
|
+
def transform_keys
|
4
|
+
return enum_for(:transform_keys) unless block_given?
|
5
|
+
result = self.class.new
|
6
|
+
each_key do |key|
|
7
|
+
result[yield(key)] = self[key]
|
8
|
+
end
|
9
|
+
result
|
10
|
+
end
|
11
|
+
|
12
|
+
def _deep_transform_keys_in_object(object, &block)
|
13
|
+
case object
|
14
|
+
when Hash
|
15
|
+
object.each_with_object({}) do |(key, value), result|
|
16
|
+
result[yield(key)] = _deep_transform_keys_in_object(value, &block)
|
17
|
+
end
|
18
|
+
when Array
|
19
|
+
object.map {|e| _deep_transform_keys_in_object(e, &block) }
|
20
|
+
else
|
21
|
+
object
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def deep_transform_keys(&block)
|
26
|
+
_deep_transform_keys_in_object(self, &block)
|
27
|
+
end
|
28
|
+
|
29
|
+
def symbolize_keys
|
30
|
+
transform_keys { |key| key.to_sym rescue key }
|
31
|
+
end
|
32
|
+
|
33
|
+
def deep_symbolize_keys
|
34
|
+
deep_transform_keys { |key| key.to_sym rescue key }
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class String
|
2
|
+
|
3
|
+
def demodulize
|
4
|
+
if i = self.rindex("::")
|
5
|
+
self[(i + 2)..-1]
|
6
|
+
else
|
7
|
+
self
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def underscore
|
12
|
+
return self unless /[A-Z-]|::/.match?(self)
|
13
|
+
word = self.gsub("::".freeze, "/".freeze)
|
14
|
+
word.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2'.freeze)
|
15
|
+
word.gsub!(/([a-z\d])([A-Z])/, '\1_\2'.freeze)
|
16
|
+
word.tr!("-".freeze, "_".freeze)
|
17
|
+
word.downcase!
|
18
|
+
word
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module ApiAiWrapper
|
2
|
+
|
3
|
+
# https://api.ai/docs/reference/agent/query#query_parameters_and_json_fields
|
4
|
+
class MeaningExtractor < ApiAiWrapper::Components::ExtractorComponent
|
5
|
+
|
6
|
+
# https://api.ai/docs/reference/agent/query#post_query
|
7
|
+
# Retrieves the meaning of a utterance
|
8
|
+
# options can contain (in accordance with API reference) :
|
9
|
+
# - contexts
|
10
|
+
# - location
|
11
|
+
# - timezone
|
12
|
+
# - lang
|
13
|
+
# - sessionId
|
14
|
+
def post_query(query, options = {})
|
15
|
+
set_headers
|
16
|
+
body = {
|
17
|
+
query: query,
|
18
|
+
lang: self.engine.locale,
|
19
|
+
sessionId: SecureRandom.hex
|
20
|
+
}.merge(options)
|
21
|
+
endpoint_url = URI.join(self.engine.base_url, "query?v=#{self.engine.version}")
|
22
|
+
|
23
|
+
res = self.post(endpoint_url, body.to_json)
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module ApiAiWrapper::Trainers
|
2
|
+
|
3
|
+
# https://api.ai/docs/reference/agent/entities#overview
|
4
|
+
# https://api.ai/docs/reference/agent/entities#entity_object
|
5
|
+
class EntityTrainer < ApiAiWrapper::Components::TrainerComponent
|
6
|
+
|
7
|
+
# https://api.ai/docs/reference/agent/entities#get_entities
|
8
|
+
# Retrieves all entities for a given token
|
9
|
+
def get_entities
|
10
|
+
endpoint_url = URI.join(self.engine.base_url, "entities?v=#{self.engine.version}")
|
11
|
+
|
12
|
+
self.get(endpoint_url, {})
|
13
|
+
end
|
14
|
+
|
15
|
+
# https://api.ai/docs/reference/agent/entities#get_entitieseid
|
16
|
+
# Retrieves entity info
|
17
|
+
# eid can either be the ID or the entity NAME
|
18
|
+
def get_entity(eid)
|
19
|
+
endpoint_url = URI.join(self.engine.base_url, "entities/#{eid}?v=#{self.engine.version}")
|
20
|
+
|
21
|
+
self.get(endpoint_url, {})
|
22
|
+
end
|
23
|
+
|
24
|
+
# https://docs.api.ai/docs/entities#post-entities
|
25
|
+
# Creates an entity with the corresponding entries
|
26
|
+
def post_entity(name, entries)
|
27
|
+
body = {
|
28
|
+
name: name,
|
29
|
+
entries: entries
|
30
|
+
}
|
31
|
+
endpoint_url = URI.join(self.engine.base_url, "entities?v=#{self.engine.version}")
|
32
|
+
|
33
|
+
self.post(endpoint_url, body.to_json)
|
34
|
+
end
|
35
|
+
|
36
|
+
# https://api.ai/docs/reference/agent/entities#post_entitieseidentries
|
37
|
+
# Allows to add entries to en existing entity
|
38
|
+
# eid can either be the ID or the entity NAME
|
39
|
+
def post_entity_entries(eid, entries)
|
40
|
+
endpoint_url = URI.join(self.engine.base_url, "entities/#{eid}/entries?v=#{self.engine.version}")
|
41
|
+
|
42
|
+
self.post(endpoint_url, entries.to_json)
|
43
|
+
end
|
44
|
+
|
45
|
+
# https://api.ai/docs/reference/agent/entities#put_entitieseid
|
46
|
+
# Update an entity
|
47
|
+
def put_entity(eid, options = {})
|
48
|
+
endpoint_url = URI.join(self.engine.base_url, "entities/#{eid}?v=#{self.engine.version}")
|
49
|
+
|
50
|
+
self.put(endpoint_url, options.to_json)
|
51
|
+
end
|
52
|
+
|
53
|
+
# https://api.ai/docs/reference/agent/entities#put_entitieseid
|
54
|
+
# Update an entity's entries
|
55
|
+
def put_entity_entries(eid, entries)
|
56
|
+
body = { entries: entries }
|
57
|
+
endpoint_url = URI.join(self.engine.base_url, "entities/#{eid}/entries?v=#{self.engine.version}")
|
58
|
+
|
59
|
+
self.put(endpoint_url, entries.to_json)
|
60
|
+
end
|
61
|
+
|
62
|
+
# https://api.ai/docs/reference/agent/entities#delete_entitieseid
|
63
|
+
# Delete an entity
|
64
|
+
# eid can either be the ID or the entity NAME
|
65
|
+
def delete_entity(eid)
|
66
|
+
endpoint_url = URI.join(self.engine.base_url, "entities/#{eid}?v=#{self.engine.version}")
|
67
|
+
|
68
|
+
self.delete(endpoint_url, {})
|
69
|
+
end
|
70
|
+
|
71
|
+
# https://api.ai/docs/reference/agent/entities#delete_entitieseidentries
|
72
|
+
# Delete an entity's entries
|
73
|
+
# eid can either be the ID or the entity NAME
|
74
|
+
# entries is an array of reference values (e.g. ["blue", "red"] for entity "color")
|
75
|
+
def delete_entity_entries(eid, entries)
|
76
|
+
body = { entries: entries }
|
77
|
+
endpoint_url = URI.join(self.engine.base_url, "entities/#{eid}/entries?v=#{self.engine.version}")
|
78
|
+
|
79
|
+
self.delete(endpoint_url, body.to_json)
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module ApiAiWrapper::Trainers
|
2
|
+
|
3
|
+
# https://api.ai/docs/reference/agent/intents#overview
|
4
|
+
# https://api.ai/docs/reference/agent/intents#intent_object
|
5
|
+
class IntentTrainer < ApiAiWrapper::Components::TrainerComponent
|
6
|
+
|
7
|
+
# https://api.ai/docs/reference/agent/intents#get_intents
|
8
|
+
# Fetches all intents for a given token
|
9
|
+
def get_intents
|
10
|
+
set_headers
|
11
|
+
endpoint_url = URI.join(self.engine.base_url, "intents?v=#{self.engine.version}")
|
12
|
+
|
13
|
+
res = self.engine.client.get(endpoint_url, {}, self.engine.headers)
|
14
|
+
|
15
|
+
JSON.parse(res.body)
|
16
|
+
end
|
17
|
+
|
18
|
+
# https://api.ai/docs/reference/agent/intents#get_intentsiid
|
19
|
+
# Retrieves intent info
|
20
|
+
def get_intent(iid)
|
21
|
+
set_headers
|
22
|
+
endpoint_url = URI.join(self.engine.base_url, "intents/#{iid}?v=#{self.engine.version}")
|
23
|
+
|
24
|
+
res = self.engine.client.get(endpoint_url, {}, self.engine.headers)
|
25
|
+
|
26
|
+
JSON.parse(res.body)
|
27
|
+
end
|
28
|
+
|
29
|
+
# https://api.ai/docs/reference/agent/intents#post_intents
|
30
|
+
# Creates an intent
|
31
|
+
# options can contain (in accordance with API reference) :
|
32
|
+
# - contexts
|
33
|
+
# - templates
|
34
|
+
# - responses
|
35
|
+
def post_intent(name, user_says_data, options = {})
|
36
|
+
set_headers
|
37
|
+
body = options.merge({
|
38
|
+
name: name,
|
39
|
+
auto: true, # ML activated
|
40
|
+
userSays: user_says_data
|
41
|
+
})
|
42
|
+
endpoint_url = URI.join(self.engine.base_url, "intents?v=#{self.engine.version}")
|
43
|
+
|
44
|
+
res = self.engine.client.post(endpoint_url, body.to_json, self.engine.headers)
|
45
|
+
|
46
|
+
JSON.parse(res.body)
|
47
|
+
end
|
48
|
+
|
49
|
+
# https://api.ai/docs/reference/agent/intents#put_intentsiid
|
50
|
+
# Update an intent
|
51
|
+
def put_intent(iid, options = {})
|
52
|
+
set_headers
|
53
|
+
endpoint_url = URI.join(self.engine.base_url, "intents/#{iid}?v=#{self.engine.version}")
|
54
|
+
|
55
|
+
res = self.engine.client.put(endpoint_url, options.to_json, self.engine.headers)
|
56
|
+
|
57
|
+
JSON.parse(res.body)
|
58
|
+
end
|
59
|
+
|
60
|
+
# https://api.ai/docs/reference/agent/entities#delete_entitieseid
|
61
|
+
# Delete an intent
|
62
|
+
def delete_intent(iid)
|
63
|
+
set_headers
|
64
|
+
endpoint_url = URI.join(self.engine.base_url, "intents/#{iid}?v=#{self.engine.version}")
|
65
|
+
|
66
|
+
res = self.engine.client.delete(endpoint_url, {}, self.engine.headers)
|
67
|
+
|
68
|
+
JSON.parse(res.body)
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe ApiAiWrapper::Components::Component do
|
4
|
+
|
5
|
+
let :engine do
|
6
|
+
ApiAiWrapper::Engine.new({
|
7
|
+
client_token: "some-token",
|
8
|
+
developer_token: "some-token"
|
9
|
+
})
|
10
|
+
end
|
11
|
+
|
12
|
+
let :component do
|
13
|
+
comp = ApiAiWrapper::Components::Component.new
|
14
|
+
comp.engine = engine
|
15
|
+
comp
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "http_verbs" do
|
19
|
+
it "should define http_verb methods get/post/put/delete" do
|
20
|
+
[:get, :post, :put, :delete].each do |http_verb|
|
21
|
+
expect(component.respond_to?(http_verb)).to be true
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should call #raise_if_unauthorized for each http_verb methods" do
|
26
|
+
expect(engine.intent_trainer).to receive(:raise_if_unauthorized).exactly(4).times
|
27
|
+
allow(engine.intent_trainer).to receive(:set_headers).and_call_original
|
28
|
+
allow(engine.intent_trainer).to receive(:handle_response)
|
29
|
+
|
30
|
+
[:get, :post, :put, :delete].each do |http_verb|
|
31
|
+
stub_call(engine, "some-url", { method: http_verb })
|
32
|
+
engine.intent_trainer.send(http_verb, URI.join(ApiAiWrapper::Constants::DEFAULT_BASE_URL, "some-url"))
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should call #set_headers for each http_verb methods" do
|
37
|
+
allow(engine.intent_trainer).to receive(:raise_if_unauthorized)
|
38
|
+
expect(engine.intent_trainer).to receive(:set_headers).exactly(4).times.and_call_original
|
39
|
+
allow(engine.intent_trainer).to receive(:handle_response)
|
40
|
+
|
41
|
+
[:get, :post, :put, :delete].each do |http_verb|
|
42
|
+
stub_call(engine, "some-url", { method: http_verb })
|
43
|
+
engine.intent_trainer.send(http_verb, URI.join(ApiAiWrapper::Constants::DEFAULT_BASE_URL, "some-url"))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should call #handle_response for each http_verb methods" do
|
48
|
+
allow(engine.intent_trainer).to receive(:raise_if_unauthorized)
|
49
|
+
allow(engine.intent_trainer).to receive(:set_headers).and_call_original
|
50
|
+
expect(engine.intent_trainer).to receive(:handle_response).exactly(4).times.and_call_original
|
51
|
+
|
52
|
+
[:get, :post, :put, :delete].each do |http_verb|
|
53
|
+
stub_call(engine, "some-url", { method: http_verb })
|
54
|
+
engine.intent_trainer.send(http_verb, URI.join(ApiAiWrapper::Constants::DEFAULT_BASE_URL, "some-url"))
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "#handle_response(response)" do
|
60
|
+
context "when API.AI call is successful (code is 200)" do
|
61
|
+
it "should return JSON parsed response" do
|
62
|
+
response = { "status" => { "code" => 200, "errorType" => "success" } }
|
63
|
+
|
64
|
+
expect(component.send(:handle_response, response)).to eq(response.deep_symbolize_keys)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context "when API.AI call is in error (code is not 200)" do
|
69
|
+
it "should return JSON parsed response" do
|
70
|
+
response = { "status" => { "code" => 203, "errorType" => "problem", "errorDetails" => "an error" } }
|
71
|
+
|
72
|
+
expect {
|
73
|
+
component.send(:handle_response, response)
|
74
|
+
}.to raise_error(ApiAiWrapper::Errors::Engine::ApiError)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe ApiAiWrapper::Components::ExtractorComponent do
|
4
|
+
|
5
|
+
describe "#raise_if_unauthorized" do
|
6
|
+
it "should not raise if call is client_token is present" do
|
7
|
+
engine = ApiAiWrapper::Engine.new(client_token: "some-token")
|
8
|
+
expect {
|
9
|
+
engine.meaning_extractor.raise_if_unauthorized
|
10
|
+
}.not_to raise_error
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should raise if call is client_token is blank" do
|
14
|
+
engine = ApiAiWrapper::Engine.new(client_token: nil, developer_token: "some-token")
|
15
|
+
expect {
|
16
|
+
engine.meaning_extractor.raise_if_unauthorized
|
17
|
+
}.to raise_error(ApiAiWrapper::Errors::Engine::MissingToken)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#set_headers" do
|
22
|
+
let :engine do
|
23
|
+
ApiAiWrapper::Engine.new({
|
24
|
+
client_token: "some-token-1",
|
25
|
+
developer_token: "some-token"
|
26
|
+
})
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should set authorization and content type headers correctly" do
|
30
|
+
expect(engine.headers).to be_nil
|
31
|
+
|
32
|
+
engine.meaning_extractor.set_headers
|
33
|
+
|
34
|
+
expect(engine.headers).to eq({ "Authorization" => "Bearer some-token-1", "Content-Type" => "application/json; charset=utf-8" })
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe ApiAiWrapper::Components::TrainerComponent do
|
4
|
+
|
5
|
+
describe "#raise_if_unauthorized" do
|
6
|
+
it "should not raise if call is developer_token is present" do
|
7
|
+
engine = ApiAiWrapper::Engine.new(developer_token: "some-token")
|
8
|
+
expect {
|
9
|
+
engine.entity_trainer.raise_if_unauthorized
|
10
|
+
}.not_to raise_error
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should raise if call is developer_token is blank" do
|
14
|
+
engine = ApiAiWrapper::Engine.new(client_token: "some-token", developer_token: nil)
|
15
|
+
expect {
|
16
|
+
engine.entity_trainer.raise_if_unauthorized
|
17
|
+
}.to raise_error(ApiAiWrapper::Errors::Engine::MissingToken)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#set_headers" do
|
22
|
+
let :engine do
|
23
|
+
ApiAiWrapper::Engine.new({
|
24
|
+
client_token: "some-token",
|
25
|
+
developer_token: "some-token-1"
|
26
|
+
})
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should set authorization and content type headers correctly" do
|
30
|
+
expect(engine.headers).to be_nil
|
31
|
+
|
32
|
+
engine.intent_trainer.set_headers
|
33
|
+
|
34
|
+
expect(engine.headers).to eq({ "Authorization" => "Bearer some-token-1", "Content-Type" => "application/json; charset=utf-8" })
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe ApiAiWrapper::Engine do
|
4
|
+
|
5
|
+
let :engine do
|
6
|
+
ApiAiWrapper::Engine.new({
|
7
|
+
client_token: "some-token",
|
8
|
+
developer_token: "some-token"
|
9
|
+
})
|
10
|
+
end
|
11
|
+
|
12
|
+
let :default_params do
|
13
|
+
{ client_token: "some-token", developer_token: "some-token" }
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#initialize" do
|
17
|
+
|
18
|
+
it "should instantiate a HTTPClient as a 'client' accessor" do
|
19
|
+
expect(engine.client).to be_instance_of(HTTPClient)
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "client_timeout" do
|
23
|
+
it "should instantiate a default 'client_timeout' accessor as DEFAULT_CLIENT_TIMEOUT" do
|
24
|
+
expect(engine.client.receive_timeout).to eq(ApiAiWrapper::Constants::DEFAULT_CLIENT_TIMEOUT)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should instantiate a 'client_timeout' accessor when specified in options" do
|
28
|
+
expect(ApiAiWrapper::Engine.new(default_params.merge({ client_timeout: 1000 })).client.receive_timeout).to eq(1000)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "locale" do
|
33
|
+
it "should instantiate a default 'locale' accessor as en" do
|
34
|
+
expect(engine.locale).to eq(ApiAiWrapper::Constants::DEFAULT_LOCALE)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should instantiate a 'locale' accessor when specified in options" do
|
38
|
+
expect(ApiAiWrapper::Engine.new(default_params.merge({ locale: "fr" })).locale).to eq("fr")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should instantiate the correct default base url as 'base_url' accessor" do
|
43
|
+
expect(engine.base_url).to eq(ApiAiWrapper::Constants::DEFAULT_BASE_URL)
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "version" do
|
47
|
+
it "should instantiate a default 'version' accessor" do
|
48
|
+
expect(engine.version).to eq(ApiAiWrapper::Constants::DEFAULT_VERSION)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should instantiate a 'locale' accessor when specified in options" do
|
52
|
+
expect(ApiAiWrapper::Engine.new(default_params.merge({ version: "some-version" })).version).to eq("some-version")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "tokens" do
|
57
|
+
it "should instantiate a 'client_token' accessor when specified in options" do
|
58
|
+
expect(ApiAiWrapper::Engine.new({ client_token: "some-token" }).client_token).to eq("some-token")
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should instantiate a 'developer_token' accessor when specified in options" do
|
62
|
+
expect(ApiAiWrapper::Engine.new({ developer_token: "some-token" }).developer_token).to eq("some-token")
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should raise MissingToken error if no token is present" do
|
66
|
+
expect { ApiAiWrapper::Engine.new }.to raise_error(ApiAiWrapper::Errors::Engine::MissingTokens)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "class autoloading" do
|
71
|
+
it "should instantiate an EntityTrainer as 'entity_trainer' accessor" do
|
72
|
+
expect(engine.entity_trainer).to be_instance_of(ApiAiWrapper::Trainers::EntityTrainer)
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should instantiate an IntentTrainer as 'intent_trainer' accessor" do
|
76
|
+
expect(engine.intent_trainer).to be_instance_of(ApiAiWrapper::Trainers::IntentTrainer)
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should instantiate an MeaningExtractor as 'meaning_extractor' accessor" do
|
80
|
+
expect(engine.meaning_extractor).to be_instance_of(ApiAiWrapper::MeaningExtractor)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe ApiAiWrapper::MeaningExtractor do
|
4
|
+
|
5
|
+
let :engine do
|
6
|
+
ApiAiWrapper::Engine.new({
|
7
|
+
client_token: "some-token",
|
8
|
+
developer_token: "some-token"
|
9
|
+
})
|
10
|
+
end
|
11
|
+
|
12
|
+
let :meaning_extractor do
|
13
|
+
engine.meaning_extractor
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#post_query(query, options = {})" do
|
17
|
+
it "should send a call to the correct endpoint with appropriate headers and body params" do
|
18
|
+
stub_call(engine, "query?v=#{engine.version}", {
|
19
|
+
method: :post,
|
20
|
+
request_body: {
|
21
|
+
query: "some-query",
|
22
|
+
lang: engine.locale,
|
23
|
+
sessionId: "some-session-id"
|
24
|
+
}.to_json
|
25
|
+
})
|
26
|
+
meaning_extractor.post_query("some-query", { sessionId: "some-session-id" })
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe ApiAiWrapper::Trainers::EntityTrainer do
|
4
|
+
|
5
|
+
let :engine do
|
6
|
+
ApiAiWrapper::Engine.new({
|
7
|
+
client_token: "some-token",
|
8
|
+
developer_token: "some-token"
|
9
|
+
})
|
10
|
+
end
|
11
|
+
|
12
|
+
let :entity_trainer do
|
13
|
+
engine.entity_trainer
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#get_entities" do
|
17
|
+
it "should send a call to the correct endpoint with appropriate headers" do
|
18
|
+
stub_call(engine, "entities")
|
19
|
+
entity_trainer.get_entities
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "#get_entity(eid)" do
|
24
|
+
it "should send a call to the correct endpoint with appropriate headers" do
|
25
|
+
stub_call(engine, "entities/some-id")
|
26
|
+
entity_trainer.get_entity("some-id")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#post_entity(name, entries)" do
|
31
|
+
it "should send a call to the correct endpoint with appropriate headers and body params" do
|
32
|
+
stub_call(engine, "entities?v=#{engine.version}", {
|
33
|
+
method: :post,
|
34
|
+
request_body: {
|
35
|
+
name: "some-name",
|
36
|
+
entries: "some-entries"
|
37
|
+
}.to_json
|
38
|
+
})
|
39
|
+
entity_trainer.post_entity("some-name", "some-entries")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "#post_entity_entries(eid, entries)" do
|
44
|
+
it "should send a call to the correct endpoint with appropriate headers and body params" do
|
45
|
+
stub_call(engine, "entities/some-id/entries?v=#{engine.version}", {
|
46
|
+
method: :post,
|
47
|
+
request_body: "some-entries".to_json
|
48
|
+
})
|
49
|
+
entity_trainer.post_entity_entries("some-id", "some-entries")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "#put_entity(eid, options = {})" do
|
54
|
+
it "should send a call to the correct endpoint with appropriate headers and body params" do
|
55
|
+
stub_call(engine, "entities/some-id?v=#{engine.version}", {
|
56
|
+
method: :put,
|
57
|
+
request_body: {
|
58
|
+
name: "new-name"
|
59
|
+
}.to_json
|
60
|
+
})
|
61
|
+
entity_trainer.put_entity("some-id", { name: "new-name" })
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "#put_entity_entries(eid, entries)" do
|
66
|
+
it "should send a call to the correct endpoint with appropriate headers and body params" do
|
67
|
+
stub_call(engine, "entities/some-id/entries?v=#{engine.version}", {
|
68
|
+
method: :put,
|
69
|
+
request_body: {
|
70
|
+
entries: "new-entries"
|
71
|
+
}.to_json
|
72
|
+
})
|
73
|
+
entity_trainer.put_entity_entries("some-id", { entries: "new-entries" })
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "#delete_entity(eid)" do
|
78
|
+
it "should send a call to the correct endpoint with appropriate headers and body params" do
|
79
|
+
stub_call(engine, "entities/some-id?v=#{engine.version}", {
|
80
|
+
method: :delete
|
81
|
+
})
|
82
|
+
entity_trainer.delete_entity("some-id")
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "#delete_entity_entries(eid, entries)" do
|
87
|
+
it "should send a call to the correct endpoint with appropriate headers and body params" do
|
88
|
+
stub_call(engine, "entities/some-id/entries?v=#{engine.version}", {
|
89
|
+
method: :delete,
|
90
|
+
request_body: {
|
91
|
+
entries: "entries-to-delete"
|
92
|
+
}
|
93
|
+
})
|
94
|
+
entity_trainer.delete_entity_entries("some-id", "entries-to-delete")
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe ApiAiWrapper::Trainers::IntentTrainer do
|
4
|
+
|
5
|
+
let :engine do
|
6
|
+
ApiAiWrapper::Engine.new({
|
7
|
+
client_token: "some-token",
|
8
|
+
developer_token: "some-token"
|
9
|
+
})
|
10
|
+
end
|
11
|
+
|
12
|
+
let :intent_trainer do
|
13
|
+
engine.intent_trainer
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#get_intents" do
|
17
|
+
it "should send a call to the correct endpoint with appropriate headers" do
|
18
|
+
stub_call(engine, "intents")
|
19
|
+
intent_trainer.get_intents
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "#get_intent(iid)" do
|
24
|
+
it "should send a call to the correct endpoint with appropriate headers" do
|
25
|
+
stub_call(engine, "intents/some-id")
|
26
|
+
intent_trainer.get_intent("some-id")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#post_intent(name, user_says_data, options = {})" do
|
31
|
+
it "should send a call to the correct endpoint with appropriate headers and body params" do
|
32
|
+
stub_call(engine, "intents?v=#{engine.version}", {
|
33
|
+
method: :post,
|
34
|
+
request_body: {
|
35
|
+
name: "some-name",
|
36
|
+
auto: true,
|
37
|
+
userSays: "some-data"
|
38
|
+
}.to_json
|
39
|
+
})
|
40
|
+
intent_trainer.post_intent("some-name", "some-data")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "#put_intent(iid, options = {})" do
|
45
|
+
it "should send a call to the correct endpoint with appropriate headers and body params" do
|
46
|
+
stub_call(engine, "intents/some-id?v=#{engine.version}", {
|
47
|
+
method: :put,
|
48
|
+
request_body: {
|
49
|
+
name: "new-name"
|
50
|
+
}.to_json
|
51
|
+
})
|
52
|
+
intent_trainer.put_intent("some-id", { name: "new-name" })
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "#delete_intent(iid)" do
|
57
|
+
it "should send a call to the correct endpoint with appropriate headers and body params" do
|
58
|
+
stub_call(engine, "intents/some-id?v=#{engine.version}", {
|
59
|
+
method: :delete
|
60
|
+
})
|
61
|
+
intent_trainer.delete_intent("some-id")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
# This file was generated by the `rails generate rspec:install` command. Conventionally, all
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
+
# The generated `.rspec` file contains `--require spec_helper` which will cause
|
4
|
+
# this file to always be loaded, without a need to explicitly require it in any
|
5
|
+
# files.
|
6
|
+
#
|
7
|
+
# Given that it is always loaded, you are encouraged to keep this file as
|
8
|
+
# light-weight as possible. Requiring heavyweight dependencies from this file
|
9
|
+
# will add to the boot time of your test suite on EVERY test run, even for an
|
10
|
+
# individual file that may not need all of that loaded. Instead, consider making
|
11
|
+
# a separate helper file that requires the additional dependencies and performs
|
12
|
+
# the additional setup, and require it from the spec files that actually need
|
13
|
+
# it.
|
14
|
+
#
|
15
|
+
# The `.rspec` file also contains a few flags that are not defaults but that
|
16
|
+
# users commonly want.
|
17
|
+
#
|
18
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
19
|
+
RSpec.configure do |config|
|
20
|
+
# rspec-expectations config goes here. You can use an alternate
|
21
|
+
# assertion/expectation library such as wrong or the stdlib/minitest
|
22
|
+
# assertions if you prefer.
|
23
|
+
config.expect_with :rspec do |expectations|
|
24
|
+
# This option will default to `true` in RSpec 4. It makes the `description`
|
25
|
+
# and `failure_message` of custom matchers include text for helper methods
|
26
|
+
# defined using `chain`, e.g.:
|
27
|
+
# be_bigger_than(2).and_smaller_than(4).description
|
28
|
+
# # => "be bigger than 2 and smaller than 4"
|
29
|
+
# ...rather than:
|
30
|
+
# # => "be bigger than 2"
|
31
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
32
|
+
end
|
33
|
+
|
34
|
+
# rspec-mocks config goes here. You can use an alternate test double
|
35
|
+
# library (such as bogus or mocha) by changing the `mock_with` option here.
|
36
|
+
config.mock_with :rspec do |mocks|
|
37
|
+
# Prevents you from mocking or stubbing a method that does not exist on
|
38
|
+
# a real object. This is generally recommended, and will default to
|
39
|
+
# `true` in RSpec 4.
|
40
|
+
mocks.verify_partial_doubles = true
|
41
|
+
end
|
42
|
+
|
43
|
+
# These two settings work together to allow you to limit a spec run
|
44
|
+
# to individual examples or groups you care about by tagging them with
|
45
|
+
# `:focus` metadata. When nothing is tagged with `:focus`, all examples
|
46
|
+
# get run.
|
47
|
+
config.filter_run :focus
|
48
|
+
config.run_all_when_everything_filtered = true
|
49
|
+
|
50
|
+
# Allows RSpec to persist some state between runs in order to support
|
51
|
+
# the `--only-failures` and `--next-failure` CLI options. We recommend
|
52
|
+
# you configure your source control system to ignore this file.
|
53
|
+
config.example_status_persistence_file_path = "spec/examples.txt"
|
54
|
+
|
55
|
+
# Limits the available syntax to the non-monkey patched syntax that is
|
56
|
+
# recommended. For more details, see:
|
57
|
+
# - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
|
58
|
+
# - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
|
59
|
+
# - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
|
60
|
+
config.disable_monkey_patching!
|
61
|
+
|
62
|
+
# Many RSpec users commonly either run the entire suite or an individual
|
63
|
+
# file, and it's useful to allow more verbose output when running an
|
64
|
+
# individual spec file.
|
65
|
+
if config.files_to_run.one?
|
66
|
+
# Use the documentation formatter for detailed output,
|
67
|
+
# unless a formatter has already been configured
|
68
|
+
# (e.g. via a command-line flag).
|
69
|
+
config.default_formatter = 'doc'
|
70
|
+
end
|
71
|
+
|
72
|
+
# Print the 10 slowest examples and example groups at the
|
73
|
+
# end of the spec run, to help surface which specs are running
|
74
|
+
# particularly slow.
|
75
|
+
# config.profile_examples = 10
|
76
|
+
|
77
|
+
# Run specs in random order to surface order dependencies. If you find an
|
78
|
+
# order dependency and want to debug it, you can fix the order by providing
|
79
|
+
# the seed, which is printed after each run.
|
80
|
+
# --seed 1234
|
81
|
+
config.order = :random
|
82
|
+
|
83
|
+
# Seed global randomization in this process using the `--seed` CLI option.
|
84
|
+
# Setting this allows you to use `--seed` to deterministically reproduce
|
85
|
+
# test failures related to randomization by passing the same `--seed` value
|
86
|
+
# as the one that triggered the failure.
|
87
|
+
Kernel.srand config.seed
|
88
|
+
|
89
|
+
config.color = true
|
90
|
+
end
|
91
|
+
|
92
|
+
require "simplecov"
|
93
|
+
SimpleCov.start "rails"
|
94
|
+
|
95
|
+
require "webmock/rspec"
|
96
|
+
WebMock.disable_net_connect!
|
97
|
+
|
98
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'api_ai_wrapper')
|
99
|
+
|
100
|
+
def stub_call(engine, path, options = {})
|
101
|
+
stub_request(options[:method].presence || :get, URI.join(engine.base_url, path))
|
102
|
+
.with({
|
103
|
+
headers: { "Authorization" => "Bearer some-token", "Content-Type" => "application/json; charset=utf-8" },
|
104
|
+
body: options[:request_body] || nil
|
105
|
+
})
|
106
|
+
.to_return(body: (options[:return_body].presence || { "status" => { "code" => 200, "errorType" => "success" } }.to_json))
|
107
|
+
end
|
108
|
+
|
109
|
+
def fixture_path
|
110
|
+
File.join(File.dirname(__FILE__), '..', 'spec', 'fixtures')
|
111
|
+
end
|
metadata
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: api_ai_wrapper
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Vincent Gabou
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-08-04 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: httpclient
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.8'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 2.8.0
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '2.8'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 2.8.0
|
33
|
+
description: A simple ruby library that let's any developer automate the training
|
34
|
+
process of a Natural Language Processing Engine on API.AI, and retrieve meaning
|
35
|
+
from new utterances.
|
36
|
+
email: vincent.gabou@gmail.com
|
37
|
+
executables: []
|
38
|
+
extensions: []
|
39
|
+
extra_rdoc_files: []
|
40
|
+
files:
|
41
|
+
- ".gitignore"
|
42
|
+
- Gemfile
|
43
|
+
- Gemfile.lock
|
44
|
+
- LICENSE
|
45
|
+
- README.md
|
46
|
+
- api_ai_wrapper.gemspec
|
47
|
+
- lib/api_ai_wrapper.rb
|
48
|
+
- lib/api_ai_wrapper/components/component.rb
|
49
|
+
- lib/api_ai_wrapper/components/extractor_component.rb
|
50
|
+
- lib/api_ai_wrapper/components/trainer_component.rb
|
51
|
+
- lib/api_ai_wrapper/constants.rb
|
52
|
+
- lib/api_ai_wrapper/engine.rb
|
53
|
+
- lib/api_ai_wrapper/errors.rb
|
54
|
+
- lib/api_ai_wrapper/extensions/hash.rb
|
55
|
+
- lib/api_ai_wrapper/extensions/object.rb
|
56
|
+
- lib/api_ai_wrapper/extensions/string.rb
|
57
|
+
- lib/api_ai_wrapper/meaning_extractor.rb
|
58
|
+
- lib/api_ai_wrapper/trainers/entity_trainer.rb
|
59
|
+
- lib/api_ai_wrapper/trainers/intent_trainer.rb
|
60
|
+
- spec/api_ai_wrapper/components/component_spec.rb
|
61
|
+
- spec/api_ai_wrapper/components/extractor_component_spec.rb
|
62
|
+
- spec/api_ai_wrapper/components/trainer_component_spec.rb
|
63
|
+
- spec/api_ai_wrapper/engine_spec.rb
|
64
|
+
- spec/api_ai_wrapper/meaning_extractor_spec.rb
|
65
|
+
- spec/api_ai_wrapper/trainers/entity_trainer_spec.rb
|
66
|
+
- spec/api_ai_wrapper/trainers/intent_trainer_spec.rb
|
67
|
+
- spec/spec_helper.rb
|
68
|
+
homepage: http://rubygems.org/gems/api_ai_wrapper
|
69
|
+
licenses:
|
70
|
+
- MIT
|
71
|
+
metadata: {}
|
72
|
+
post_install_message:
|
73
|
+
rdoc_options: []
|
74
|
+
require_paths:
|
75
|
+
- lib
|
76
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
requirements: []
|
87
|
+
rubyforge_project:
|
88
|
+
rubygems_version: 2.6.11
|
89
|
+
signing_key:
|
90
|
+
specification_version: 4
|
91
|
+
summary: An API.AI Ruby Wrapper
|
92
|
+
test_files: []
|