indico 0.2.5 → 0.3.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.
data/README.md CHANGED
@@ -24,7 +24,7 @@ For API key registration and setup, checkout our [quickstart guide](http://docs.
24
24
 
25
25
  Full Documentation
26
26
  ------------
27
- Detailed documentation and further code examples are available at [indico.reame.io](http://indico.readme.io/v2.0/docs/ruby)
27
+ Detailed documentation and further code examples are available at [indico.readme.io](http://indico.readme.io/v2.0/docs/ruby)
28
28
 
29
29
  Examples
30
30
  ---------
@@ -72,6 +72,46 @@ Each `Indico` method has a corresponding batch method for analyzing many example
72
72
  => [0.9899001220871786, 0.005709885173415242]
73
73
  ```
74
74
 
75
+
76
+ Calling multiple APIs with a single function
77
+ ---------
78
+ There are two multiple API functions `predict_text` and `predict_image` (and their batch counterparts). These functions are similar to the existing api functions, but take in an additional `apis` argument as an array of strings of API names (defaults to all existing apis). `predict_text` accepts a list of existing text APIs and vice versa for `predict_image`.
79
+
80
+ Accepted text API names: `text_tags, political, sentiment, language`
81
+
82
+ Accepted image API names: `fer, facial_features, image_features`
83
+
84
+ ```ruby
85
+ > require 'indico'
86
+
87
+ => true
88
+
89
+ > Indico.api_key = "YOUR_API_KEY"
90
+
91
+ => "YOUR_API_KEY"
92
+
93
+ > Indico.predict_text("Best day ever", ["sentiment", "language"])
94
+
95
+ => {"sentiment"=>0.9899001220871786, "language"=>{"Swedish"=>0.0022464881013042294, "Vietnamese"=>9.887170914498351e-05, ...}}
96
+
97
+ > Indico.batch_predict_text(["Best day ever", "Worst day ever"], ["sentiment", "language"])
98
+
99
+ => {"sentiment"=>[0.9899001220871786, 0.005709885173415242], "language"=>[{"Swedish"=>0.0022464881013042294, "Vietnamese"=>9.887170914498351e-05, "Romanian"=>0.00010661175919993216, ...}, {"Swedish"=>0.4924352805804646, "Vietnamese"=>0.028574824174911372, "Romanian"=>0.004185623723173551, "Dutch"=>0.000717033819689362, "Korean"=>0.0030093489153785826, ...}]}
100
+
101
+ > test_face = Array.new(48){Array.new(48){Array.new(3){rand(100)/100.0}}}
102
+
103
+ => [[[0.66, 0.99, 0.03], [0.42, 0.72, 0.86], [0.95, 0.44, 0.61], [0.39, 0.57, 0.4], [0.06, 0.52, 0.43], [0.11, 0.09, 0.78], [0.35, 0.69, 0.32], [0.44, 0.5, 0.26], [0.71, 0.75, 0.64], [0.91, 0.92, 0.14], [0.71, 0.98, 0.02], ..]]
104
+
105
+ > Indico.predict_image(test_face, ["fer", "facial_features"])
106
+
107
+ => {"facial_features"=>[0.0, -0.026176479280200796, 0.20707644777495776, ...], "fer"=>{"Angry"=>0.08877494466353497, "Sad"=>0.3933999409104264, "Neutral"=>0.1910612654566151, "Surprise"=>0.0346146405941845, "Fear"=>0.17682159820518667, "Happy"=>0.11532761017005204}}
108
+
109
+ > Indico.batch_predict_image([test_face, test_face], ["fer", "facial_features"])
110
+
111
+ => {"facial_features"=>[[0.0, -0.026176479280200796, 0.20707644777495776, ...], [0.0, -0.026176479280200796, 0.20707644777495776, ...]], "fer"=>[{"Angry"=>0.08877494466353497, "Sad"=>0.3933999409104264, "Neutral"=>0.1910612654566151, "Surprise"=>0.0346146405941845, "Fear"=>0.17682159820518667, "Happy"=>0.11532761017005204}, {"Angry"=>0.08877494466353497, "Sad"=>0.3933999409104264, "Neutral"=>0.1910612654566151, "Surprise"=>0.0346146405941845, "Fear"=>0.17682159820518667, "Happy"=>0.11532761017005204}]}
112
+ ```
113
+
114
+
75
115
  ## Contributing
76
116
 
77
117
  1. Fork it ( https://github.com/[my-github-username]/indico/fork )
data/indico.gemspec CHANGED
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ['lib']
20
20
 
21
21
  spec.add_runtime_dependency 'inifile', '~> 3.0.0'
22
+ spec.add_runtime_dependency 'oily_png', '~> 1.2.0'
22
23
  spec.add_development_dependency 'bundler', '~> 1.6'
23
24
  spec.add_development_dependency 'rake'
24
25
  spec.add_development_dependency 'rspec'
@@ -0,0 +1,3 @@
1
+ class IndicoError < StandardError
2
+
3
+ end
data/lib/indico/helper.rb CHANGED
@@ -1,4 +1,4 @@
1
- require 'base64'
1
+ require_relative './errors'
2
2
 
3
3
  module Indico
4
4
  private
@@ -14,24 +14,22 @@ module Indico
14
14
  def self.api_handler(data, api, config)
15
15
  server = nil
16
16
  api_key = nil
17
- unless config.nil?
18
- server = config[:cloud]
19
- api_key = config[:api_key]
20
- end
17
+
21
18
  d = {}
22
19
  d['data'] = data
23
- data_dict = JSON.dump(d)
24
20
 
25
- if api_key.nil?
26
- api_key = Indico.config['auth']
21
+ unless config.nil?
22
+ server = config[:cloud]
23
+ api_key = config[:api_key]
24
+ apis = config["apis"]
25
+ d = d.merge(config)
27
26
  end
28
27
 
29
- if server.nil?
30
- server = Indico.config['cloud']
31
- end
28
+ url = url_join((server or Indico.config['cloud']), api) +
29
+ (apis ? "?apis=" + apis.join(",") : "")
32
30
 
33
- response = make_request(url_join(server, api), data_dict,
34
- add_api_key_to_header(api_key))
31
+ response = make_request(url, JSON.dump(d),
32
+ add_api_key_to_header((api_key or Indico.config['auth'])))
35
33
 
36
34
 
37
35
  results = JSON.parse(response.body)
@@ -65,7 +63,7 @@ module Indico
65
63
  if api_key.nil?
66
64
  raise ArgumentError, 'api key is required'
67
65
  end
68
- headers = { 'Content-Type' => 'application/json', 'Accept' => 'text/plain' }
66
+ headers = HEADERS
69
67
  headers['X-ApiKey'] = api_key
70
68
  headers
71
69
  end
@@ -0,0 +1,109 @@
1
+ require 'oily_png'
2
+ require 'base64'
3
+
4
+ module Indico
5
+ def self.preprocess(image, size, batch)
6
+ # image is [[f,f,f,f, ...], ..] or [[[f,f,f],[f,f,f],[f,f,f]], ...]
7
+ if batch
8
+ # Batch Request
9
+ im_array = Array.new
10
+
11
+ # process each image
12
+ image.each do |_image|
13
+ im_array.push(preprocess(_image, size, false))
14
+ end
15
+
16
+ return im_array
17
+ end
18
+
19
+ if image.class == String
20
+ decoded_image = handle_string_input(image)
21
+ elsif image.class == Array
22
+ decoded_image = handle_array_input(image)
23
+ else
24
+ raise Exception.new("Image input must be nested array of pixels, filename, or base64 string")
25
+ end
26
+
27
+ # Resize and export base64 encoded string
28
+ return decoded_image.resize(size, size).to_data_url.gsub("data:image/png;base64," ,"")
29
+ end
30
+
31
+ def self.handle_string_input(str)
32
+ # Handles string input
33
+ if File.file?(str)
34
+ # Handling File Inputs
35
+ return ChunkyPNG::Image.from_file(str)
36
+ end
37
+
38
+ regex = %r{^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$}.match(str)
39
+ # Base 64 handling
40
+ if regex == nil
41
+ raise Exception.new("String is not a valid absolute filepath or base64 string")
42
+ else
43
+ return ChunkyPNG::Image.from_data_url("data:image/png;base64," + str.gsub("data:image/png;base64," ,""))
44
+ end
45
+ end
46
+
47
+ def self.handle_array_input(image)
48
+ # Handles properly formatting and loading array of pixels
49
+ # Single Request
50
+ warn "Warning! Array input as image will be deprecated in the next major release.\n Consider using filepaths or base64 encoded strings"
51
+
52
+ dimens = get_dimension(image)
53
+ isFloat = array_contains_float(image, dimens)
54
+
55
+ if dimens.size > 3
56
+ raise Exception.new("Nested array of image must be [[p, p, ...]] or [[[r,g,b], [r,g,b], ...]]")
57
+ end
58
+
59
+ decoded_image = ChunkyPNG::Image.new(dimens[0], dimens[1])
60
+
61
+ # Manually loading the pixels into the ChunkyImage object
62
+ (0..dimens[0] - 1).each do |x|
63
+ (0..dimens[1] - 1).each do |y|
64
+ pixel = image[x][y]
65
+ if pixel.is_a?(Array)
66
+ if isFloat
67
+ pixel.map! {|a| (255 * a).to_i}
68
+ end
69
+ decoded_image.set_pixel(x,y, ChunkyPNG::Color.rgb(pixel[0], pixel[1], pixel[2]))
70
+ else
71
+ if isFloat
72
+ pixel = (pixel * 255).to_i
73
+ end
74
+ decoded_image.set_pixel(x,y, ChunkyPNG::Color.rgb(pixel, pixel, pixel))
75
+ end
76
+ end
77
+ end
78
+
79
+ return decoded_image
80
+ end
81
+
82
+
83
+ def self.get_dimension(array)
84
+ return [] unless array.is_a?(Array)
85
+ return [array.size] + get_dimension(array[0])
86
+ end
87
+
88
+ def self.array_contains_float(array, dimens)
89
+ # Determines whether or not the array contains floats
90
+ if not array.is_a?(Array)
91
+ return array.class == Float
92
+ end
93
+ elem = array[0]
94
+ (0..dimens.size - 2).each do |i|
95
+ elem = elem[0]
96
+ end
97
+
98
+ return elem.class == Float
99
+ end
100
+
101
+ def self.get_rgb(value)
102
+ # Returns Integer encoding of RGB value used by ChunkyPNG
103
+ return [
104
+ ChunkyPNG::Color.r(value),
105
+ ChunkyPNG::Color.g(value),
106
+ ChunkyPNG::Color.b(value)
107
+ ]
108
+ end
109
+ end
@@ -0,0 +1,47 @@
1
+ require_relative './errors'
2
+
3
+ module Indico
4
+ CLIENT_TO_SERVER = {
5
+ "political" => "political",
6
+ "sentiment" => "sentiment",
7
+ "language" => "language",
8
+ "text_tags" => "texttags",
9
+ "fer" => "fer",
10
+ "facial_features" => "facialfeatures",
11
+ "image_features" => "imagefeatures"
12
+ }
13
+
14
+ SERVER_TO_CLIENT = CLIENT_TO_SERVER.invert
15
+ def self.multi(data, type, apis, allowed, batch = false, config)
16
+ converted_apis = Array.new
17
+ apis.each { |api|
18
+ if not allowed.include? api
19
+ fail api + " is not a valid api for " + type + " requests. Please use: " + allowed.join(", ")
20
+ else
21
+ converted_apis.push(CLIENT_TO_SERVER[api])
22
+ end
23
+ }
24
+
25
+ if config.nil?
26
+ config = {}
27
+ end
28
+
29
+ config["apis"] = converted_apis
30
+ response = api_handler(data, batch ? "apis/batch" : "apis", config)
31
+ results = handle_multi(response)
32
+
33
+ results
34
+ end
35
+
36
+ def self.handle_multi(results)
37
+ converted_results = Hash.new
38
+ results.each do |key, value|
39
+ if value.is_a?(Hash) && value.has_key?("results")
40
+ converted_results[SERVER_TO_CLIENT[key]] = value["results"]
41
+ else
42
+ raise IndicoError, 'unexpected result from ' + key + '\n\t' + value.fetch("error", "")
43
+ end
44
+ end
45
+ converted_results
46
+ end
47
+ end
@@ -1,4 +1,13 @@
1
1
  require 'inifile'
2
+ require_relative 'version'
3
+
4
+ HEADERS = { 'Content-Type' => 'application/json',
5
+ 'Accept' => 'application/json',
6
+ 'client-lib' => 'ruby',
7
+ 'version-number' => Indico::VERSION }
8
+ # APIS
9
+ TEXT_APIS = ["political", "sentiment", "language", "text_tags"]
10
+ IMAGE_APIS = ["fer", "facial_features", "image_features"]
2
11
 
3
12
  module Indico
4
13
  private
@@ -1,3 +1,3 @@
1
1
  module Indico
2
- VERSION = '0.2.5'
2
+ VERSION = '0.3.0'
3
3
  end
data/lib/indico.rb CHANGED
@@ -1,16 +1,13 @@
1
1
  require 'indico/version'
2
2
  require 'indico/helper'
3
+ require 'indico/image'
4
+ require 'indico/multi'
3
5
  require 'indico/settings'
4
6
  require 'uri'
5
7
  require 'json'
6
8
  require 'net/https'
7
9
 
8
10
  module Indico
9
- HEADERS = { 'Content-Type' => 'application/json',
10
- 'Accept' => 'application/json',
11
- 'client-lib' => 'ruby',
12
- 'version-number' => '0.2.5' }
13
-
14
11
  def self.api_key
15
12
  config['auth']
16
13
  end
@@ -67,27 +64,47 @@ module Indico
67
64
  api_handler(test_text, 'texttags/batch', config)
68
65
  end
69
66
 
70
- def self.fer(face, config = nil)
71
- api_handler(face, 'fer', config)
67
+ def self.fer(test_image, config = nil)
68
+ api_handler(preprocess(test_image, 48, false), 'fer', config)
69
+ end
70
+
71
+ def self.batch_fer(test_image, config = nil)
72
+ api_handler(preprocess(test_image, 48, true), 'fer/batch', config)
73
+ end
74
+
75
+ def self.facial_features(test_image, config = nil)
76
+ api_handler(preprocess(test_image, 48, false), 'facialfeatures', config)
77
+ end
78
+
79
+ def self.batch_facial_features(test_image, config = nil)
80
+ api_handler(preprocess(test_image, 48, true), 'facialfeatures/batch', config)
81
+ end
82
+
83
+ def self.image_features(test_image, config = nil)
84
+ api_handler(preprocess(test_image, 64, false), 'imagefeatures', config)
72
85
  end
73
86
 
74
- def self.batch_fer(test_text, config = nil)
75
- api_handler(test_text, 'fer/batch', config)
87
+ def self.batch_image_features(test_image, config = nil)
88
+ api_handler(preprocess(test_image, 64, true), 'imagefeatures/batch', config)
76
89
  end
77
90
 
78
- def self.facial_features(face, config = nil)
79
- api_handler(face, 'facialfeatures', config)
91
+ def self.predict_image(face, apis = IMAGE_APIS, config = nil)
92
+ api_hash = {"apis" => apis}
93
+ multi(preprocess(face, 48, false), "image", apis, IMAGE_APIS, config ? config.update(api_hash) : api_hash)
80
94
  end
81
95
 
82
- def self.batch_facial_features(test_text, config = nil)
83
- api_handler(test_text, 'facialfeatures/batch', config)
96
+ def self.predict_text(test_text, apis = TEXT_APIS, config = nil)
97
+ api_hash = {"apis" => apis}
98
+ multi(test_text, "text", apis, TEXT_APIS, config ? config.update(api_hash) : api_hash)
84
99
  end
85
100
 
86
- def self.image_features(face, config = nil)
87
- api_handler(face, 'imagefeatures', config)
101
+ def self.batch_predict_image(face, apis, config = nil)
102
+ api_hash = {"apis" => apis}
103
+ multi(preprocess(face, 48, true), "image", apis, IMAGE_APIS, true, config ? config.update(api_hash) : api_hash)
88
104
  end
89
105
 
90
- def self.batch_image_features(test_text, config = nil)
91
- api_handler(test_text, 'imagefeatures/batch', config)
106
+ def self.batch_predict_text(test_text, apis, config = nil)
107
+ api_hash = {"apis" => apis}
108
+ multi(test_text, "text", apis, TEXT_APIS, true, config ? config.update(api_hash) : api_hash)
92
109
  end
93
110
  end
Binary file
@@ -0,0 +1 @@
1
+ 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
@@ -21,7 +21,7 @@ describe Indico do
21
21
  it 'should access a private cloud' do
22
22
  expected_keys = Set.new(%w(Conservative Green Liberal Libertarian))
23
23
  data = ['Guns don\'t kill people.', ' People kill people.']
24
-
24
+
25
25
  # for mocking: use http instead of https to route requests to our public cloud
26
26
  Indico.cloud_protocol = 'http://'
27
27
  response = Indico.batch_political(data, @config_private_cloud)
@@ -104,26 +104,63 @@ describe Indico do
104
104
  it 'should tag face with correct facial expression' do
105
105
  expected_keys = Set.new(%w(Angry Sad Neutral Surprise Fear Happy))
106
106
  test_face = Array.new(48) { Array.new(48) { rand(100) / 100.0 } }
107
- response = Indico.batch_fer([test_face, test_face], @config)
107
+ silent_warnings do
108
+ response = Indico.batch_fer([test_face, test_face], @config)
108
109
 
109
- expect(Set.new(response[0].keys)).to eql(expected_keys)
110
- expect(Set.new(response[1].keys)).to eql(expected_keys)
110
+ expect(Set.new(response[0].keys)).to eql(expected_keys)
111
+ expect(Set.new(response[1].keys)).to eql(expected_keys)
112
+ end
111
113
  end
112
114
 
113
115
  it 'should tag face with correct facial features' do
114
116
  test_face = Array.new(48) { Array.new(48) { rand(100) / 100.0 } }
115
- response = Indico.batch_facial_features([test_face, test_face], @config)
116
- expect(response[0].length).to eql(48)
117
- expect(response[1].length).to eql(48)
117
+ silent_warnings do
118
+ response = Indico.batch_facial_features([test_face, test_face], @config)
119
+ expect(response[0].length).to eql(48)
120
+ expect(response[1].length).to eql(48)
121
+ end
118
122
  end
119
123
 
120
124
  it 'should tag image with correct image features' do
121
125
  test_image = Array.new(48) { Array.new(48) { rand(100) / 100.0 } }
122
- response = Indico.batch_image_features([test_image, test_image], @config)
123
- expect(response[0].length).to eql(2048)
124
- expect(response[1].length).to eql(2048)
126
+ silent_warnings do
127
+ response = Indico.batch_image_features([test_image, test_image], @config)
128
+ expect(response[0].length).to eql(2048)
129
+ expect(response[1].length).to eql(2048)
130
+ end
125
131
  end
126
132
 
133
+ it "should respond with all text apis called in batch" do
134
+ expected_keys = Set.new(TEXT_APIS)
135
+ response = Indico.batch_predict_text(["Worst movie ever."], TEXT_APIS)
136
+
137
+ expect(response.class).to eql(Hash)
138
+ expect(Set.new(response.keys)).to eql(expected_keys)
139
+ end
140
+
141
+ it "should respond with all image apis called in batch" do
142
+ test_image = Array.new(48){Array.new(48){Array.new(3){rand(100)/100.0}}}
143
+ expected_keys = Set.new(IMAGE_APIS)
144
+ silent_warnings do
145
+ response = Indico.batch_predict_image([test_image], IMAGE_APIS)
146
+
147
+ expect(response.class).to eql(Hash)
148
+ expect(Set.new(response.keys)).to eql(expected_keys)
149
+ end
150
+ end
151
+
152
+ it "should respond with all image apis called on int array in batch" do
153
+ test_image = Array.new(48){Array.new(48){Array.new(3){rand(100)}}}
154
+ expected_keys = Set.new(IMAGE_APIS)
155
+ silent_warnings do
156
+ response = Indico.batch_predict_image([test_image], IMAGE_APIS)
157
+
158
+ expect(response.class).to eql(Hash)
159
+ expect(Set.new(response.keys)).to eql(expected_keys)
160
+ end
161
+ end
162
+
163
+
127
164
  # Uncomment when frontend updated to accept image urls
128
165
  # it "should accept image urls" do
129
166
  # test_image = 'http://icons.iconarchive.com/icons/oxygen-icons.org/' +
data/spec/indico_spec.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'spec_helper'
2
2
  require 'set'
3
+ require 'oily_png'
3
4
 
4
5
  describe Indico do
5
6
  before do
@@ -18,7 +19,7 @@ describe Indico do
18
19
  it 'should tag text with correct political tags' do
19
20
  expected_keys = Set.new(%w(Conservative Green Liberal Libertarian))
20
21
  data = 'Guns don\'t kill people. People kill people.'
21
-
22
+
22
23
  # for mocking: use http to redirect requests to our public cloud endpoint
23
24
  Indico.cloud_protocol = 'http://'
24
25
  response = Indico.political(data, @config)
@@ -94,33 +95,91 @@ describe Indico do
94
95
  it 'should tag face with correct facial expression' do
95
96
  expected_keys = Set.new(%w(Angry Sad Neutral Surprise Fear Happy))
96
97
  test_face = Array.new(48) { Array.new(48) { rand(100) / 100.0 } }
97
-
98
- response = Indico.fer(test_face)
99
-
100
- expect(Set.new(response.keys)).to eql(expected_keys)
98
+ silent_warnings do
99
+ response = Indico.fer(test_face)
100
+ expect(Set.new(response.keys)).to eql(expected_keys)
101
+ end
101
102
  end
102
103
 
103
104
  it 'should tag face with correct facial features' do
104
105
  test_face = Array.new(48) { Array.new(48) { rand(100) / 100.0 } }
105
- response = Indico.facial_features(test_face)
106
-
107
- expect(response.length).to eql(48)
106
+ silent_warnings do
107
+ response = Indico.facial_features(test_face)
108
+ expect(response.length).to eql(48)
109
+ end
108
110
  end
109
111
 
110
112
  it 'should tag image with correct image features' do
111
113
  test_image = Array.new(48) { Array.new(48) { rand(100) / 100.0 } }
112
- response = Indico.image_features(test_image)
113
-
114
- expect(response.length).to eql(2048)
114
+ silent_warnings do
115
+ response = Indico.image_features(test_image)
116
+ expect(response.length).to eql(2048)
117
+ end
115
118
  end
116
119
 
117
120
  it "should tag rgb image with correct image features" do
118
121
  test_image = Array.new(48){Array.new(48){Array.new(3){rand(100)/100.0}}}
119
- response = Indico.image_features(test_image)
122
+ silent_warnings do
123
+ response = Indico.image_features(test_image)
124
+ expect(response.length).to eql(2048)
125
+ end
126
+ end
127
+
128
+ it "should be able to load image from path" do
129
+ expected_keys = Set.new(%w(Angry Sad Neutral Surprise Fear Happy))
130
+ response = Indico.fer(File.dirname(__FILE__) + "/data/happy.png")
131
+
132
+ expect(Set.new(response.keys)).to eql(expected_keys)
133
+ expect(response["Happy"]).to be > 0.5
134
+ end
120
135
 
121
- expect(response.length).to eql(2048)
136
+ it "should be able to load image from b64" do
137
+ expected_keys = Set.new(%w(Angry Sad Neutral Surprise Fear Happy))
138
+ response = Indico.fer(File.open(File.dirname(__FILE__) + "/data/happy64.txt", 'rb') { |f| f.read })
139
+
140
+ expect(Set.new(response.keys)).to eql(expected_keys)
141
+ expect(response["Happy"]).to be > 0.5
122
142
  end
123
143
 
144
+ it "should respond with all text apis called" do
145
+ expected_keys = Set.new(TEXT_APIS)
146
+ response = Indico.predict_text("Worst movie ever.", TEXT_APIS)
147
+
148
+ expect(response.class).to eql(Hash)
149
+ expect(Set.new(response.keys)).to eql(expected_keys)
150
+ end
151
+
152
+ it "should respond with all text apis called by default" do
153
+ expected_keys = Set.new(TEXT_APIS)
154
+ response = Indico.predict_text("Worst movie ever.")
155
+
156
+ expect(response.class).to eql(Hash)
157
+ expect(Set.new(response.keys)).to eql(expected_keys)
158
+ end
159
+
160
+ it "should respond with all image apis called" do
161
+ test_image = Array.new(48){Array.new(48){Array.new(3){rand(100)/100.0}}}
162
+ expected_keys = Set.new(IMAGE_APIS)
163
+ silent_warnings do
164
+ response = Indico.predict_image(test_image, IMAGE_APIS)
165
+
166
+ expect(response.class).to eql(Hash)
167
+ expect(Set.new(response.keys)).to eql(expected_keys)
168
+ end
169
+ end
170
+
171
+ it "should respond with all image apis called on int array" do
172
+ test_image = Array.new(48){Array.new(48){Array.new(3){rand(100)}}}
173
+ expected_keys = Set.new(IMAGE_APIS)
174
+ silent_warnings do
175
+ response = Indico.predict_image(test_image, IMAGE_APIS)
176
+
177
+ expect(response.class).to eql(Hash)
178
+ expect(Set.new(response.keys)).to eql(expected_keys)
179
+ end
180
+ end
181
+
182
+
124
183
  # Uncomment when frontend updated to accept image urls
125
184
  # it 'should accept image urls' do
126
185
  # response = Indico.image_features('http://icons.iconarchive.com/icons/' +
data/spec/spec_helper.rb CHANGED
@@ -1,4 +1,13 @@
1
1
  require 'indico'
2
+ require 'stringio'
3
+
4
+ def silent_warnings
5
+ old_stderr = $stderr
6
+ $stderr = StringIO.new
7
+ yield
8
+ ensure
9
+ $stderr = old_stderr
10
+ end
2
11
 
3
12
  # This file was generated by the `rspec --init` command. Conventionally, all
4
13
  # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: indico
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.5
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2015-05-28 00:00:00.000000000 Z
15
+ date: 2015-06-11 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: inifile
@@ -30,6 +30,22 @@ dependencies:
30
30
  - - ~>
31
31
  - !ruby/object:Gem::Version
32
32
  version: 3.0.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: oily_png
35
+ requirement: !ruby/object:Gem::Requirement
36
+ none: false
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: 1.2.0
41
+ type: :runtime
42
+ prerelease: false
43
+ version_requirements: !ruby/object:Gem::Requirement
44
+ none: false
45
+ requirements:
46
+ - - ~>
47
+ - !ruby/object:Gem::Version
48
+ version: 1.2.0
33
49
  - !ruby/object:Gem::Dependency
34
50
  name: bundler
35
51
  requirement: !ruby/object:Gem::Requirement
@@ -96,11 +112,16 @@ files:
96
112
  - Rakefile
97
113
  - indico.gemspec
98
114
  - lib/indico.rb
115
+ - lib/indico/errors.rb
99
116
  - lib/indico/helper.rb
117
+ - lib/indico/image.rb
118
+ - lib/indico/multi.rb
100
119
  - lib/indico/settings.rb
101
120
  - lib/indico/version.rb
102
121
  - spec/config/.indicorc.test
103
122
  - spec/config/.indicorc.test.2
123
+ - spec/data/happy.png
124
+ - spec/data/happy64.txt
104
125
  - spec/indico_batch_spec.rb
105
126
  - spec/indico_spec.rb
106
127
  - spec/settings_spec.rb