api-ai-ruby 1.1.4 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a41b09d5539b73625a590a8981fc7ab84c8684de
4
- data.tar.gz: f45732f184aeb2d8acc30f8d2847d3a211191bdc
3
+ metadata.gz: 80d81f092a618acaa74a093158d2a31df3285ad7
4
+ data.tar.gz: 4d37dbe4d5852cd4d0c8cf3c55cfdd117b6f11b8
5
5
  SHA512:
6
- metadata.gz: 1665dcdbd43e394cb047a70f1470d65b19333595c39adc1cc3307d67f0521dc0641871614df12dc6a1bd018e0d57935099c7a03a1ad37c25caab521b08ac856d
7
- data.tar.gz: 4f508ae74f7990ca232766d15aaf7f903a1c755127e82011cce5635c61b9d03f90f7084dc5985db4faea72180f9d3751cb6b2b0acc4cd87e8712aad91e0f2a8b
6
+ metadata.gz: f4e48a201428311e784ad7a43bb724dc9c83b35877790195d701cf4dd9c83c1f253099e60e7b0b0f099d86d0ca6210485cf534e24bda94555d8431ac1c960bfc
7
+ data.tar.gz: cf8f2961d2a94efe4fa1ad04af478d917b89306be8f57a1ebadbf7b88537778cec55c47efa5988841849af26d358aa88c9adeb2859685eadfabb51096685caaf
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # The API.AI ruby gem
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/api-ai-ruby.svg)](https://badge.fury.io/rb/api-ai-ruby)
4
+
3
5
  A Ruby SDK to the https://api.ai natural language processing service.
4
6
 
5
7
  ## Installation
@@ -62,7 +64,8 @@ ApiAiRuby::Client.new(
62
64
  client_access_token: 'YOUR_ACCESS_TOKEN',
63
65
  api_lang: 'FR',
64
66
  api_base_url: 'http://example.com/v1/',
65
- api_version: 'YYYYMMDD'
67
+ api_version: 'YYYYMMDD',
68
+ api_session_id: 'some_uuid_or_whatever'
66
69
  )
67
70
  ```
68
71
 
@@ -72,14 +75,80 @@ And you also can send additional data to server during request, use second param
72
75
  response = client.text_request 'Hello', :contexts => ['firstContext'], :resetContexts => true
73
76
  response = client.voice_request file, :timezone => "America/New_York"
74
77
  ```
78
+
75
79
  More information about possible parameters can be found at https://docs.api.ai/docs/query page
76
80
 
81
+ ## User Entities
82
+
83
+ Another possibility is to send and retrieve [custom entities](https://docs.api.ai/docs/userentities) to the server.
84
+
85
+ You can do it along with **query** request
86
+ ```ruby
87
+ client.text_request 'call Mozart', entities: [
88
+ {
89
+ name: 'contacts',
90
+ entries: [
91
+ ApiAiRuby::Entry.new('Mozart', %w(Mozart Wolfgang)),
92
+ ApiAiRuby::Entry.new('Salieri', %w(Salieri Antonio))
93
+ ]
94
+ }
95
+ ]
96
+
97
+ # the same without ApiAiRuby::Entry wrapper
98
+
99
+ client.text_request 'call Mozart', entities: [
100
+ {
101
+ name: 'contacts',
102
+ entries: [
103
+ {value: 'Mozart', synonyms: %w(Mozart Wolfgang))},
104
+ {value: 'Salieri', synonyms: %w(Salieri Antonio))},
105
+ ]
106
+ }
107
+ ]
108
+
109
+ ```
110
+
111
+ Or with separate **user_entities_request** object with full CRUD support:
112
+
113
+ ```ruby
114
+
115
+ # preparations
116
+ entries_composers = [
117
+ ApiAiRuby::Entry.new('Mozart', %w(Mozart Wolfgang)),
118
+ ApiAiRuby::Entry.new('Salieri', %w(Salieri Antonio))
119
+ ]
120
+
121
+ entries_unknown = [
122
+ ApiAiRuby::Entry.new('John Doe', %w(John Unknown)),
123
+ ApiAiRuby::Entry.new('Jane Doe', %w(Jane))
124
+ ]
125
+
126
+ entity_contacts = ApiAiRuby::Entity.new('contacts', [entries_composers])
127
+
128
+ # let's go
129
+ uer = client.user_entities_request
130
+ uer.create(contacts) # or uer.create([entity1, entity2...])
131
+
132
+ client.text_request 'call Mozart' # will work
133
+
134
+ uer.update('contacts', entries_unknown)
135
+
136
+ client.text_request 'call Mozart' # will NOT work
137
+ client.text_request 'call John' # will work
138
+
139
+ uer.retrieve('contacts') # will return current state of user entity
140
+ uer.delete('contacts') # will remove user entities for given session
141
+
142
+ ```
143
+
144
+
77
145
  #Error handling
78
146
  **ApiAiRuby::Client** currently able to raise two kind of errors: **ApiAiRuby::ClientError** (due to configuration mismatch) and **ApiAiRuby::RequestError** in case of something goes wrong during request. For both kind of errors you can get **error.message** (as usual) and **ApiAiRuby::RequestError** can additionally give you code of server error (you can get it with **error.code**)
79
147
 
80
148
 
81
149
  #Changelog
82
150
 
151
+ * 1.2.0 - added configurable session_id and separate user_entities (post) request
83
152
  * 1.1.4 - removed unused dependency and updated default API version
84
153
  * 1.1.3 - fixed non-correctly serialized parameters in new contexts during query send process
85
154
  * 1.1.2 - fixed compatibility with ruby version less then 2.1.6
data/lib/api-ai-ruby.rb CHANGED
@@ -2,7 +2,10 @@ require 'api-ai-ruby/constants'
2
2
  require 'api-ai-ruby/client'
3
3
  require 'api-ai-ruby/request_error'
4
4
  require 'api-ai-ruby/client_error'
5
- require 'api-ai-ruby/request_query'
6
- require 'api-ai-ruby/text_request'
7
- require 'api-ai-ruby/voice_request'
5
+ require 'api-ai-ruby/request/request_query'
6
+ require 'api-ai-ruby/request/text_request'
7
+ require 'api-ai-ruby/request/voice_request'
8
+ require 'api-ai-ruby/models/entry'
9
+ require 'api-ai-ruby/models/entity'
10
+ require 'api-ai-ruby/crud/user_entity_request'
8
11
 
@@ -1,16 +1,23 @@
1
+ require 'securerandom'
2
+
1
3
  module ApiAiRuby
2
4
  class Client
3
5
  attr_accessor :client_access_token, :subscription_key
4
- attr_writer :user_agent, :api_version, :api_lang, :api_base_url
6
+ attr_writer :user_agent, :api_version, :api_lang, :api_base_url, :api_session_id
5
7
 
6
8
  # Initializes a new Client object
7
9
  #
8
10
  # @param options [Hash]
9
- # @return [Twitter::Client]
11
+ # @return [ApiAiRuby::Client]
10
12
  def initialize(options = {})
11
13
  options.each do |key, value|
12
14
  instance_variable_set("@#{key}", value)
13
15
  end
16
+
17
+ if !(options.key? :api_session_id)
18
+ @api_session_id = SecureRandom.uuid
19
+ end
20
+
14
21
  yield(self) if block_given?
15
22
  end
16
23
 
@@ -31,6 +38,10 @@ module ApiAiRuby
31
38
  @api_version ||= ApiAiRuby::Constants::DEFAULT_API_VERSION
32
39
  end
33
40
 
41
+ def api_session_id
42
+ @api_session_id
43
+ end
44
+
34
45
  # @return [Hash]
35
46
  def credentials
36
47
  {
@@ -55,5 +66,20 @@ module ApiAiRuby
55
66
  ApiAiRuby::VoiceRequest.new(self, options).perform
56
67
  end
57
68
 
69
+ # @param entity_name [String]
70
+ # @param entries [ApiAiRuby:Entry[]]
71
+ # @param options [Hash]
72
+
73
+ def user_entities_request #entity_name, entries, options = {}
74
+ ApiAiRuby::UserEntitiesRequest.new(self);
75
+ # raise ApiAiRuby::ClientError.new('Entity name required') if entity_name.nil?
76
+ # raise ApiAiRuby::ClientError.new('Entity entries array required') if !entries.nil? && entries.is_a?(Array)
77
+ # raise ApiAiRuby::ClientError.new('Entity name required') if !(options.has_key?(:entries) && options[:entries].is_a?(Array))
78
+ # options[:name] = entity_name
79
+ # options[:entries] = entries
80
+ # options[:extend] = options[:extend] || false
81
+ # ApiAiRuby::UserEntitiesRequest.new(self, options).perform
82
+ end
83
+
58
84
  end
59
85
  end
@@ -1,6 +1,6 @@
1
1
  module ApiAiRuby
2
2
  class Constants
3
- VERSION = '1.1.4'
3
+ VERSION = '1.2.0'
4
4
  DEFAULT_BASE_URL = 'https://api.api.ai/v1/'
5
5
  DEFAULT_API_VERSION = '20150910'
6
6
  DEFAULT_CLIENT_LANG = 'en'
@@ -0,0 +1,55 @@
1
+ module ApiAiRuby
2
+ class UserEntitiesRequest < ApiAiRuby::RequestQuery
3
+
4
+ def initialize(client, options = {})
5
+ super client, options
6
+ @crud_base_uri = client.api_base_url + 'userEntities'
7
+ @uri = @crud_base_uri
8
+ end
9
+
10
+
11
+ def create(argument)
12
+ if !(argument && (argument.is_a?(Array) || argument.is_a?(Hash) || argument.is_a?(ApiAiRuby::Entity)))
13
+ raise ApiAiRuby::ClientError.new('Argument should be array of Entities or single Entity object')
14
+ end
15
+ @uri = @crud_base_uri
16
+ @request_method = :post
17
+ @options[:entities] = argument.is_a?(Array) ? argument : [argument]
18
+ response = self.perform
19
+ @options.delete(:entities)
20
+ response
21
+ end
22
+
23
+ def retrieve(name)
24
+ raise ApiAiRuby::ClientError.new('Entity name required') if !name
25
+ @request_method = :get
26
+ @uri = @crud_base_uri + '/' + name
27
+ self.perform
28
+ end
29
+
30
+ def update(name, entries, extend = false)
31
+
32
+ raise ApiAiRuby::ClientError.new('Entity name required') if !name
33
+
34
+ @options[:extend] = extend
35
+ @options[:name] = name
36
+ @options[:entries] = entries
37
+
38
+ @request_method = :put
39
+ @uri = @crud_base_uri + '/' + name
40
+ response = self.perform
41
+ @options.delete(:extend)
42
+ @options.delete(:name)
43
+ @options.delete(:entries)
44
+ response
45
+ end
46
+
47
+ def delete(name)
48
+ raise ApiAiRuby::ClientError.new('Entity name required') if !name
49
+ @request_method = :delete
50
+ @uri = @crud_base_uri + '/' + name
51
+ self.perform
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,24 @@
1
+ module ApiAiRuby
2
+ class Entity
3
+ attr_accessor :name, :entries
4
+
5
+ # @param name [String]
6
+ # @param entries [Array]
7
+ def initialize (name, entries)
8
+ @name = name
9
+ @entries = entries
10
+ end
11
+
12
+ def to_json(*args)
13
+ {
14
+ :name => name,
15
+ :entries => entries
16
+ }.to_json(*args)
17
+ end
18
+
19
+ def addEntry(value, synonyms)
20
+ @entries.push new ApiAiRuby::Entry(value, synonyms)
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,19 @@
1
+ module ApiAiRuby
2
+ class Entry
3
+ attr_accessor :value, :synonyms
4
+
5
+ # @param value [String]
6
+ # @param synonyms [Array]
7
+ def initialize (value, synonyms)
8
+ @value = value
9
+ @synonyms = synonyms
10
+ end
11
+
12
+ def to_json(*args)
13
+ {
14
+ :value => @value,
15
+ :synonyms => @synonyms
16
+ }.to_json(*args)
17
+ end
18
+ end
19
+ end
@@ -13,7 +13,7 @@ module ApiAiRuby
13
13
  @client = client
14
14
  @uri = client.api_base_url + 'query?v=' + client.api_version
15
15
  @request_method = :post
16
- options[:lang] = client.api_lang
16
+ options[:sessionId] = client.api_session_id
17
17
  @options = options
18
18
  @headers = {
19
19
  Authorization: 'Bearer ' + client.client_access_token,
@@ -22,7 +22,13 @@ module ApiAiRuby
22
22
 
23
23
  # @return [Array, Hash]
24
24
  def perform
25
- options_key = @options.has_key?(:voiceData) ? :form : :json
25
+
26
+ if @options.has_key?(:voiceData)
27
+ options_key = :form
28
+ else
29
+ options_key = (@request_method === :get) ? :params : :json
30
+ end
31
+
26
32
  response = HTTP.with(@headers).public_send(@request_method, @uri.to_s, options_key => @options)
27
33
  response_body = symbolize_keys!(response.parse)
28
34
  response_headers = response.headers
@@ -34,7 +40,7 @@ module ApiAiRuby
34
40
 
35
41
  def fail_or_return_response_body(code, body)
36
42
  error = false
37
- if code != 200 || body[:status][:code] != 200
43
+ if code != 200 || (body[:status] && body[:status][:code] && body[:status][:code] != 200)
38
44
  error = ApiAiRuby::RequestError.new body[:status][:errorDetails], body[:status][:code]
39
45
  end
40
46
  fail(error) if error
@@ -1,6 +1,7 @@
1
1
  module ApiAiRuby
2
2
  class TextRequest < ApiAiRuby::RequestQuery
3
3
  def initialize (client, options={})
4
+ options[:lang] = client.api_lang
4
5
  super client, options
5
6
  end
6
7
  end
@@ -8,8 +8,8 @@ module ApiAiRuby
8
8
  # @param options [Hash]
9
9
  # @return [ApiAiRuby::VoiceRequest]
10
10
  def initialize(client, options = {})
11
+ options[:lang] = client.api_lang
11
12
  super client, options
12
-
13
13
  file = options.delete(:file)
14
14
  options = {
15
15
  :request => options.to_json,
@@ -1,27 +1,30 @@
1
1
  require 'helper'
2
2
 
3
3
  describe 'api' do
4
- let (:client) { ApiAiRuby::Client.new(:client_access_token => '3485a96fb27744db83e78b8c4bc9e7b7')}
4
+ before(:all) { @client = ApiAiRuby::Client.new(
5
+ :client_access_token => '3485a96fb27744db83e78b8c4bc9e7b7',
6
+ :api_session_id => 'testsession'
7
+ )}
5
8
 
6
9
  it 'should return response' do
7
- response = client.text_request 'Hello'
10
+ response = @client.text_request 'Hello'
8
11
  expect(response[:result][:resolvedQuery]).to eq 'Hello'
9
12
  expect(response[:result][:action]).to eq 'greeting'
10
13
  end
11
14
 
12
15
  it 'should use input contexts' do
13
- response = client.text_request 'Hello', :resetContexts => true
16
+ response = @client.text_request 'Hello', :resetContexts => true
14
17
  expect(response[:result][:action]).to eq 'greeting'
15
18
 
16
- response = client.text_request 'Hello', :contexts => ['firstContext'], :resetContexts => true
19
+ response = @client.text_request 'Hello', :contexts => ['firstContext'], :resetContexts => true
17
20
  expect(response[:result][:action]).to eq 'firstGreeting'
18
21
 
19
- response = client.text_request 'Hello', :contexts => ['secondContext'], :resetContexts => true
22
+ response = @client.text_request 'Hello', :contexts => ['secondContext'], :resetContexts => true
20
23
  expect(response[:result][:action]).to eq 'secondGreeting'
21
24
  end
22
25
 
23
26
  it 'should return output contexts' do
24
- response = client.text_request 'weather', :resetContexts => true
27
+ response = @client.text_request 'weather', :resetContexts => true
25
28
  expect(response[:result][:action]).to eq 'showWeather'
26
29
  expect(response[:result][:contexts]).not_to be_nil
27
30
  expect(response[:result][:contexts].any? {|context| context[:name] == 'weather'}).to be true
@@ -33,15 +36,70 @@ describe 'api' do
33
36
  end
34
37
 
35
38
  it 'should send voiceData to API' do
36
- expect(client.voice_request(File.new(fixture_path + '/hello.wav'))[:result][:resolvedQuery]).to eq 'hello'
39
+ expect(@client.voice_request(File.new(fixture_path + '/hello.wav'))[:result][:resolvedQuery]).to eq 'hello'
37
40
  end
38
41
 
39
42
  it 'should correctly set contexts with parameters' do
40
- client.text_request 'Hello', :resetContexts => true
41
- response = client.text_request 'hello', contexts: [{ name: 'user', parameters: { first_name: 'Johnny' }}]
43
+ @client.text_request 'Hello', :resetContexts => true
44
+ response = @client.text_request 'hello', contexts: [{ name: 'user', parameters: { first_name: 'Johnny' }}]
42
45
  expect(response[:result][:contexts]).not_to be_nil
43
46
  expect(response[:result][:contexts][0][:name]).to eq 'user'
44
47
  expect(response[:result][:contexts][0][:parameters][:first_name]).to eq 'Johnny'
45
48
  end
46
49
 
50
+ it 'should use custom entities' do
51
+ response = @client.text_request 'hi nori', entities: [
52
+ {
53
+ name: 'dwarfs',
54
+ entries: [
55
+ ApiAiRuby::Entry.new('Ori', %w(ori Nori)),
56
+ {value: 'bifur', synonyms: %w(Bofur Bombur)}
57
+ ]
58
+ }
59
+ ]
60
+
61
+ expect(response[:result][:action]).to eq 'say_hi'
62
+ expect(response[:result][:fulfillment][:speech]). to eq 'hi Bilbo, I am Ori'
63
+ end
64
+
65
+ describe 'userEntities endpoint' do
66
+
67
+ before(:all) { @uer = @client.user_entities_request}
68
+
69
+ let(:entity1) {
70
+ ApiAiRuby::Entity.new 'dwarfs', [ApiAiRuby::Entry.new('giur', %w(Giur Amaldur))]
71
+ }
72
+
73
+ let(:entries) {
74
+ [ApiAiRuby::Entry.new('mami', %w(Mami Nami))]
75
+ }
76
+
77
+ it 'should create custom entities through separate request' do
78
+ @uer.create(entity1)
79
+ response = @client.text_request 'hi Amaldur'
80
+ expect(response[:result][:action]).to eq 'say_hi'
81
+ expect(response[:result][:fulfillment][:speech]). to eq 'hi Bilbo, I am giur'
82
+ end
83
+
84
+ it 'should update custom entities through separate request' do
85
+ @uer.update('dwarfs', entries)
86
+ response = @client.text_request 'hi Nami'
87
+ expect(response[:result][:action]).to eq 'say_hi'
88
+ expect(response[:result][:fulfillment][:speech]). to eq 'hi Bilbo, I am mami'
89
+ end
90
+
91
+ it 'should retrieve custom enitities' do
92
+ response = @uer.retrieve('dwarfs')
93
+ expect(response[:name]).to eq 'dwarfs'
94
+ expect(response[:entries][0][:value]).to eq 'mami'
95
+ end
96
+
97
+ it 'should remove custom entities' do
98
+ @uer.delete('dwarfs')
99
+ expect{@uer.retrieve('dwarfs')}.to raise_error(ApiAiRuby::RequestError)
100
+ end
101
+
102
+ end
103
+
104
+
47
105
  end
@@ -38,13 +38,23 @@ describe ApiAiRuby::Client do
38
38
  expect(client.api_base_url).to eq ApiAiRuby::Constants::DEFAULT_BASE_URL
39
39
  expect(client.api_version).to eq ApiAiRuby::Constants::DEFAULT_API_VERSION
40
40
  expect(client.api_lang).to eq ApiAiRuby::Constants::DEFAULT_CLIENT_LANG
41
+ expect(client.api_session_id).to be_a(String)
41
42
  end
42
43
 
43
44
  it 'correctly creates client with given properties' do
44
- client = ApiAiRuby::Client.new(subscription_key: 'SK', client_access_token: 'CS', api_lang: 'RU', api_base_url: 'http://localhost', api_version: '1234')
45
+ client = ApiAiRuby::Client.new(
46
+ subscription_key: 'SK',
47
+ client_access_token: 'CS',
48
+ api_lang: 'RU',
49
+ api_base_url: 'http://localhost',
50
+ api_version: '1234',
51
+ api_session_id: '555'
52
+ )
53
+
45
54
  expect(client.api_base_url).to eq 'http://localhost'
46
55
  expect(client.api_version).to eq '1234'
47
56
  expect(client.api_lang).to eq 'RU'
57
+ expect(client.api_session_id).to eq '555'
48
58
  end
49
59
 
50
60
 
@@ -0,0 +1,8 @@
1
+ require 'helper'
2
+
3
+ describe ApiAiRuby::Client do
4
+
5
+ # let (:client) { ApiAiRuby::Client.new(:client_access_token => 'CS')}
6
+ # @todo: add configuration tests
7
+
8
+ end
data/spec/helper.rb CHANGED
@@ -6,7 +6,7 @@ SimpleCov.formatters = [SimpleCov::Formatter::HTMLFormatter, Coveralls::SimpleCo
6
6
  SimpleCov.start do
7
7
  add_filter '/spec/'
8
8
  add_filter '/vendor/'
9
- minimum_coverage(99.57)
9
+ minimum_coverage(95)
10
10
  end
11
11
 
12
12
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: api-ai-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.4
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - api.ai
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-09-02 00:00:00.000000000 Z
11
+ date: 2016-09-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -70,14 +70,18 @@ files:
70
70
  - lib/api-ai-ruby/client.rb
71
71
  - lib/api-ai-ruby/client_error.rb
72
72
  - lib/api-ai-ruby/constants.rb
73
+ - lib/api-ai-ruby/crud/user_entity_request.rb
74
+ - lib/api-ai-ruby/models/entity.rb
75
+ - lib/api-ai-ruby/models/entry.rb
76
+ - lib/api-ai-ruby/request/request_query.rb
77
+ - lib/api-ai-ruby/request/text_request.rb
78
+ - lib/api-ai-ruby/request/voice_request.rb
73
79
  - lib/api-ai-ruby/request_error.rb
74
- - lib/api-ai-ruby/request_query.rb
75
- - lib/api-ai-ruby/text_request.rb
76
- - lib/api-ai-ruby/voice_request.rb
77
80
  - spec/api-ai-ruby/api_spec.rb
78
81
  - spec/api-ai-ruby/client_spec.rb
79
82
  - spec/api-ai-ruby/error_spec.rb
80
83
  - spec/api-ai-ruby/text_request_spec.rb
84
+ - spec/api-ai-ruby/user_entities_request_spec.rb
81
85
  - spec/api-ai-ruby/voice_request_spec.rb
82
86
  - spec/fixtures/hello.wav
83
87
  - spec/helper.rb
@@ -110,6 +114,7 @@ test_files:
110
114
  - spec/api-ai-ruby/client_spec.rb
111
115
  - spec/api-ai-ruby/error_spec.rb
112
116
  - spec/api-ai-ruby/text_request_spec.rb
117
+ - spec/api-ai-ruby/user_entities_request_spec.rb
113
118
  - spec/api-ai-ruby/voice_request_spec.rb
114
119
  - spec/fixtures/hello.wav
115
120
  - spec/helper.rb