Skip to content

Commit de5c9c2

Browse files
committed
[+] first version
1 parent 6ed6bff commit de5c9c2

20 files changed

+411
-23
lines changed

.gitignore

+6
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@
1414
.repl_history
1515
build/
1616

17+
## Specific to IDEA
18+
api-ai-ruby.iml
19+
.idea
20+
21+
1722
## Documentation cache and generated files:
1823
/.yardoc/
1924
/_yardoc/
@@ -23,6 +28,7 @@ build/
2328
## Environment normalisation:
2429
/.bundle/
2530
/lib/bundler/man/
31+
Gemfile.lock
2632

2733
# for a library or gem, you might want to ignore these files since the code is
2834
# intended to run in multiple environments; otherwise, check them in:

Gemfile

+15-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,18 @@
11
source 'https://rubygems.org'
22

3-
# Specify your gem's dependencies in gem_sample_pruby.gemspec
3+
#gem 'jruby-openssl', platforms: :jruby
4+
gem 'rake'
5+
gem 'yard'
6+
7+
group :development do
8+
9+
end
10+
11+
group :test do
12+
gem 'coveralls'
13+
gem 'rspec', '>= 2.14'
14+
gem 'simplecov', '>= 0.9'
15+
gem 'webmock'
16+
end
17+
418
gemspec

README.md

+43-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,44 @@
1-
api-ai-ruby
2-
===========
1+
# The API.AI ruby gem
2+
3+
A Ruby SDK to the https://api.ai natural language processing service.
4+
5+
## Installation
6+
gem install api-ai-ruby
7+
8+
## Basic Usage
9+
10+
Just pass correct credentials to ApiAiRuby::Client constructor
11+
12+
```ruby
13+
client = ApiAiRuby::Client.new(
14+
:client_access_token => 'YOUR_ACCESS_TOKEN',
15+
:subscription_key => 'YOUR_SUBSCRIPTION_KEY'
16+
)
17+
```
18+
After that you can send text requests to the https://api.ai with command
19+
20+
```ruby
21+
response = client.text_request 'hello!'
22+
```
23+
24+
And voice requests with file stream
25+
26+
```ruby
27+
file = File.new 'hello.wav'
28+
response = client.voice_request(file)
29+
```
30+
31+
```
32+
...
33+
response[:result][:resolvedQuery] => 'hello'
34+
...
35+
```
36+
37+
38+
39+
40+
41+
42+
43+
344

4-
Ruby SDK for api.ai

api-ai-ruby.gemspec

+15-12
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,26 @@
11
# coding: utf-8
22
lib = File.expand_path('../lib', __FILE__)
33
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4-
require 'api-ai-ruby/version'
4+
require 'api-ai-ruby/constants'
55

66
Gem::Specification.new do |spec|
7-
spec.name = "api-ai-ruby"
8-
spec.version = GemSamplePruby::VERSION
9-
spec.authors = ["TODO: put author names"]
10-
spec.email = ["TODO: put Email addresses"]
11-
spec.summary = %q{TODO: Write a short summary. Required.}
12-
spec.description = %q{TODO: Write a longer description. Optional.}
13-
spec.homepage = ""
14-
spec.license = "MIT"
7+
spec.name = 'api-ai-ruby'
8+
spec.version = ApiAiRuby::Constants::VERSION
9+
spec.authors = ['api.ai']
10+
spec.email = ['[email protected]']
11+
spec.summary = %q{ruby SDK for https://api.ai }
12+
spec.description = %q{Plugin makes it easy to integrate your Ruby application with https://api.ai natural language processing service.}
13+
spec.homepage = 'https://api.ai'
14+
spec.license = 'Apache 2.0 License'
1515

1616
spec.files = `git ls-files -z`.split("\x0")
1717
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
1818
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19-
spec.require_paths = ["lib"]
19+
spec.require_paths = ['lib']
20+
21+
spec.add_development_dependency 'bundler', '~> 1.7'
22+
spec.add_development_dependency 'rake', '~> 10.0'
23+
spec.add_dependency 'http', '~> 0.9.4'
24+
spec.add_dependency 'http-form_data', '~> 1.0'
2025

21-
spec.add_development_dependency "bundler", "~> 1.7"
22-
spec.add_development_dependency "rake", "~> 10.0"
2326
end

lib/api-ai-ruby.rb

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
class ApiAiRuby
2-
end
3-
4-
require "api-ai-ruby/version"
1+
require 'api-ai-ruby/constants'
2+
require 'api-ai-ruby/client'
3+
require 'api-ai-ruby/request_error'
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'
58

lib/api-ai-ruby/client.rb

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
module ApiAiRuby
2+
class Client
3+
attr_accessor :client_access_token, :subscription_key
4+
attr_writer :user_agent, :api_version, :api_lang, :api_base_url
5+
6+
# Initializes a new Client object
7+
#
8+
# @param options [Hash]
9+
# @return [Twitter::Client]
10+
def initialize(options = {})
11+
options.each do |key, value|
12+
instance_variable_set("@#{key}", value)
13+
end
14+
yield(self) if block_given?
15+
end
16+
17+
# @return [String]
18+
def user_agent
19+
@user_agent ||= "ApiAiRubyGem/#{ApiAiRuby::Constants::VERSION}"
20+
end
21+
22+
def api_base_url
23+
@api_base_url ||= ApiAiRuby::Constants::DEFAULT_BASE_URL
24+
end
25+
26+
def api_lang
27+
@api_lang ||= ApiAiRuby::Constants::DEFAULT_CLIENT_LANG
28+
end
29+
30+
def api_version
31+
@api_version ||= ApiAiRuby::Constants::DEFAULT_API_VERSION
32+
end
33+
34+
# @return [Hash]
35+
def credentials
36+
{
37+
client_access_token: client_access_token,
38+
subscription_key: subscription_key
39+
}
40+
end
41+
42+
# @return [Boolean]
43+
def credentials?
44+
credentials.values.all?
45+
end
46+
47+
def text_request (query = '', options = {})
48+
raise ApiAiRuby::ClientError.new('Credentials missing') if !credentials?
49+
options[:query] = query
50+
ApiAiRuby::TextRequest.new(self, options).perform
51+
end
52+
53+
def voice_request(file_stream, options = {})
54+
raise ApiAiRuby::ClientError.new('Credentials missing') if !credentials?
55+
options[:file] = file_stream
56+
ApiAiRuby::VoiceRequest.new(self, options).perform
57+
end
58+
59+
end
60+
end

lib/api-ai-ruby/client_error.rb

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module ApiAiRuby
2+
class ClientError < StandardError
3+
4+
end
5+
end

lib/api-ai-ruby/constants.rb

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module ApiAiRuby
2+
class Constants
3+
VERSION = '1.0.0'
4+
DEFAULT_BASE_URL = 'https://api.api.ai/v1/'
5+
DEFAULT_API_VERSION = '20150204'
6+
DEFAULT_CLIENT_LANG = 'en'
7+
end
8+
end

lib/api-ai-ruby/request_error.rb

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
module ApiAiRuby
2+
class RequestError < StandardError
3+
#return [Integer]
4+
attr_reader :code
5+
6+
# Initializes a new Error object
7+
#
8+
# @param message [Exception, String]
9+
# @param code [Integer]
10+
# @return [ApiAiRuby::RequestError]
11+
def initialize(message = '', code = nil)
12+
super(message)
13+
@code = code
14+
end
15+
16+
end
17+
end

lib/api-ai-ruby/request_query.rb

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
require 'http'
2+
require 'http/form_data'
3+
4+
module ApiAiRuby
5+
class RequestQuery
6+
7+
attr_accessor :client, :headers, :options, :request_method, :uri
8+
9+
# @param client [ApiAiRuby::Client]
10+
# @param options [Hash]
11+
# @return [ApiAiRuby::TextRequest]
12+
13+
def initialize(client, options = {})
14+
@client = client
15+
@uri = client.api_base_url + 'query?v=' + client.api_version
16+
@request_method = :post
17+
options[:lang] = client.api_lang
18+
@options = options
19+
@headers = {
20+
'Authorization': 'Bearer ' + client.client_access_token,
21+
'ocp-apim-subscription-key': 'Bearer ' + client.client_access_token
22+
}
23+
end
24+
25+
# @return [Array, Hash]
26+
def perform
27+
options_key = @request_method == :get ? :params : :form
28+
response = HTTP.with(@headers).public_send(@request_method, @uri.to_s, options_key => @options)
29+
response_body = symbolize_keys!(response.parse)
30+
response_headers = response.headers
31+
fail_or_return_response_body(response.code, response_body)
32+
end
33+
34+
private
35+
36+
37+
def fail_or_return_response_body(code, body)
38+
error = false
39+
if code != 200 || body[:status][:code] != 200
40+
error = ApiAiRuby::RequestError.new body[:status][:errorDetails], body[:status][:code]
41+
end
42+
fail(error) if error
43+
body
44+
end
45+
46+
def symbolize_keys!(object)
47+
if object.is_a?(Array)
48+
object.each_with_index do |val, index|
49+
object[index] = symbolize_keys!(val)
50+
end
51+
elsif object.is_a?(Hash)
52+
object.keys.each do |key|
53+
object[key.to_sym] = symbolize_keys!(object.delete(key))
54+
end
55+
end
56+
object
57+
end
58+
59+
end
60+
end

lib/api-ai-ruby/text_request.rb

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module ApiAiRuby
2+
class TextRequest < ApiAiRuby::RequestQuery
3+
def initialize (client, options={})
4+
super client, options
5+
@request_method = :get
6+
end
7+
end
8+
end

lib/api-ai-ruby/version.rb

-3
This file was deleted.

lib/api-ai-ruby/voice_request.rb

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
require 'json'
2+
3+
module ApiAiRuby
4+
class VoiceRequest < ApiAiRuby::RequestQuery
5+
6+
7+
# @param client [ApiAiRuby::Client]
8+
# @param options [Hash]
9+
# @return [ApiAiRuby::VoiceRequest]
10+
def initialize(client, options = {})
11+
super client, options
12+
13+
file = options.delete(:file)
14+
options = {
15+
:request => options.to_json,
16+
:voiceData => HTTP::FormData::File.new(file, filename: File.basename(file))
17+
}
18+
@options = options
19+
self
20+
end
21+
22+
end
23+
end

spec/api-ai-ruby/api_spec.rb

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
require 'helper'
2+
3+
describe 'api' do
4+
let (:client) { ApiAiRuby::Client.new(:client_access_token => '3485a96fb27744db83e78b8c4bc9e7b7', :subscription_key => 'cb9693af-85ce-4fbf-844a-5563722fc27f')}
5+
6+
it 'should return response' do
7+
response = client.text_request 'Hello'
8+
expect(response[:result][:resolvedQuery]).to eq 'Hello'
9+
expect(response[:result][:action]).to eq 'greeting'
10+
end
11+
12+
it 'should use input contexts' do
13+
response = client.text_request 'Hello', :resetContexts => true
14+
expect(response[:result][:action]).to eq 'greeting'
15+
16+
response = client.text_request 'Hello', :contexts => ['firstContext'], :resetContexts => true
17+
expect(response[:result][:action]).to eq 'firstGreeting'
18+
19+
response = client.text_request 'Hello', :contexts => ['secondContext'], :resetContexts => true
20+
expect(response[:result][:action]).to eq 'secondGreeting'
21+
end
22+
23+
it 'should return output contexts' do
24+
response = client.text_request 'weather', :resetContexts => true
25+
expect(response[:result][:action]).to eq 'showWeather'
26+
expect(response[:result][:contexts]).not_to be_nil
27+
expect(response[:result][:contexts].any? {|context| context[:name] == 'weather'}).to be true
28+
end
29+
30+
it 'should response with error on wrong credentials' do
31+
client = ApiAiRuby::Client.new(subscription_key: 'SK', client_access_token: 'CS')
32+
expect {client.text_request}.to raise_error(ApiAiRuby::RequestError)
33+
end
34+
35+
it 'should send voiceData to API' do
36+
expect(client.voice_request(File.new(fixture_path + '/hello.wav'))[:result][:resolvedQuery]).to eq 'hello'
37+
end
38+
end

0 commit comments

Comments
 (0)