api-ai-ruby 1.1.4 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
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