kairos-api 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +2 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +62 -0
  9. data/Rakefile +1 -0
  10. data/kairos.gemspec +33 -0
  11. data/lib/kairos.rb +10 -0
  12. data/lib/kairos/client.rb +114 -0
  13. data/lib/kairos/configuration.rb +43 -0
  14. data/lib/kairos/version.rb +3 -0
  15. data/spec/kairos/client_spec.rb +65 -0
  16. data/spec/kairos/configuration_spec.rb +28 -0
  17. data/spec/kairos/detect_spec.rb +51 -0
  18. data/spec/kairos/enroll_spec.rb +68 -0
  19. data/spec/kairos/gallery_list_all_spec.rb +32 -0
  20. data/spec/kairos/gallery_remove_subject_spec.rb +50 -0
  21. data/spec/kairos/gallery_view_spec.rb +32 -0
  22. data/spec/kairos/recognize_spec.rb +97 -0
  23. data/spec/kairos/version_spec.rb +7 -0
  24. data/spec/spec_helper.rb +14 -0
  25. data/spec/vcr/detect.yml +124 -0
  26. data/spec/vcr/detect_with_missing_parameters.yml +42 -0
  27. data/spec/vcr/detect_with_no_faces_in_image.yml +42 -0
  28. data/spec/vcr/enroll.yml +44 -0
  29. data/spec/vcr/enroll_with_invalid_image_url.yml +44 -0
  30. data/spec/vcr/enroll_with_missing_parameters.yml +43 -0
  31. data/spec/vcr/gallery_list_all.yml +39 -0
  32. data/spec/vcr/gallery_remove_subject.yml +43 -0
  33. data/spec/vcr/gallery_remove_subject_with_missing_parameters.yml +43 -0
  34. data/spec/vcr/gallery_remove_subject_with_unmatched_subject.yml +43 -0
  35. data/spec/vcr/gallery_view.yml +43 -0
  36. data/spec/vcr/recognize.yml +47 -0
  37. data/spec/vcr/recognize_with_invalid_image_url.yml +44 -0
  38. data/spec/vcr/recognize_with_missing_parameters.yml +44 -0
  39. data/spec/vcr/recognize_with_unrecognizable_image.yml +44 -0
  40. data/spec/vcr/recognize_with_url_and_gallery_name.yml +50 -0
  41. metadata +263 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 60d71f53ebc7fcbeda278dcddb8b4ff4b41b0dd7
4
+ data.tar.gz: 8e6ddb4107be8be6ecb4980df08916da31c9fb21
5
+ SHA512:
6
+ metadata.gz: 09692f660ee32c292dab10c7e8ae7b501761cc1b9433a37396aaef9c8229d4fdf48079bf6b09c72488d15ceef01046ade03938b9b06673739f9c8935f84a8548
7
+ data.tar.gz: 5ca4bd9a3fcd21a84adfd1e9c66fdff743761dd11c053df0059b95438723cb4b7270eebe5700804b3008d57e21ba560216824a15220981cfb195203037325182
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --colour
2
+ --format progress
@@ -0,0 +1 @@
1
+ kairos
@@ -0,0 +1 @@
1
+ ruby-2.1.1
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in kairos.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Frank Kany
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,62 @@
1
+ # Kairos
2
+
3
+ Ruby gem for the Kairos facial recognition API - https://developer.kairos.io/
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'kairos-api'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install kairos-api
18
+
19
+ ## Usage
20
+ https://developer.kairos.io/docs
21
+
22
+ 1. Kairos::Client.enroll(:url => 'https://some.url.com/to_some.jpg', :subject_id => 'gemtest', :gallery_name => 'testgallery'):
23
+
24
+ Takes an image and stores it as a face template into a gallery you define
25
+
26
+ $ require 'kairos'
27
+
28
+ $ client = Kairos::Client.new(:app_id => '1234', :app_key => 'abcde1234')
29
+
30
+ $ client.enroll(:url => 'https://some.url.com/to_some.jpg', :subject_id => 'gemtest', :gallery_name => 'testgallery')
31
+
32
+ 2. Kairos::Client.recognize(:url => 'https://some.image.url/123abc.jpg', :gallery_name => 'randomgallery', :threshold => '.2', :max_num_results => '5'):
33
+ - Takes an image and tries to match it against the already enrolled images in a gallery you define
34
+
35
+ 3. Kairos::Client.detect(:url => 'https://some.url.com/to_some.jpg', :selector => 'FULL'):
36
+ - Takes an image and returns the facial features found within it
37
+
38
+ 4. Kairos::Client.gallery_list_all:
39
+ - Lists out all the galleries you have subjects enrolled in
40
+
41
+ 5. Kairos::Client.gallery_view(:gallery_name => 'testgallery'):
42
+ - Lists out all the subjects you have enrolled in a specified gallery
43
+
44
+ 6. Kairos::Client.gallery_remove_subject(:gallery_name => 'randomgallery', :subject_id => 'image123abc'):
45
+ - Removes a subject from a specified gallery
46
+
47
+ ## To Do List
48
+ 1) Trim unnessary gem dependencies
49
+ 2) Expand documentation
50
+ 3) Expand test specs to cover more scenarios and edge cases
51
+ 4) DRY up code where possible
52
+
53
+ ## Contributing
54
+
55
+ 1. Fork it
56
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
57
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
58
+ 4. Push to the branch (`git push origin my-new-feature`)
59
+ 5. Create new Pull Request
60
+
61
+ ## References
62
+ Thank you to gregmoreno for creating this api template - https://github.com/gregmoreno/awesome
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,33 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'kairos/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "kairos-api"
8
+ spec.version = Kairos::VERSION
9
+ spec.authors = ["Frank Kany"]
10
+ spec.email = ["frankkany@gmail.com"]
11
+ spec.description = %q{Ruby gem for the Kairos facial recognition API}
12
+ spec.summary = %q{Ruby gem for the Kairos facial recognition API}
13
+ spec.homepage = "https://github.com/kany/kairos-api"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec", "~> 2.6"
24
+ spec.add_development_dependency "webmock", '~> 1.6'
25
+ spec.add_development_dependency "pry"
26
+ spec.add_development_dependency "vcr"
27
+ spec.add_development_dependency "typhoeus"
28
+
29
+ spec.add_runtime_dependency "faraday", "~> 0.8.0"
30
+ spec.add_runtime_dependency "faraday_middleware", "~> 0.8.7"
31
+ spec.add_runtime_dependency "hashie", "~> 1.2.0"
32
+ spec.add_runtime_dependency "multi_json", "~> 1.3"
33
+ end
@@ -0,0 +1,10 @@
1
+ require "kairos/version"
2
+ require "kairos/configuration"
3
+ require "kairos/client"
4
+
5
+ require "faraday"
6
+ require "faraday_middleware"
7
+
8
+ module Kairos
9
+ extend Configuration
10
+ end
@@ -0,0 +1,114 @@
1
+ require 'multi_json'
2
+ require 'hashie'
3
+ require 'json'
4
+
5
+ module Kairos
6
+ class Client
7
+ # Define the same set of accessors as the Kairos module
8
+ attr_accessor *Configuration::VALID_CONFIG_KEYS
9
+
10
+ def initialize(options={})
11
+ # Merge the config values from the module and those passed
12
+ # to the client.
13
+ merged_options = Kairos.options.merge(options)
14
+
15
+ # Copy the merged values to this client and ignore those
16
+ # not part of our configuration
17
+ Configuration::VALID_CONFIG_KEYS.each do |key|
18
+ send("#{key}=", merged_options[key])
19
+ end
20
+ end
21
+
22
+ # Enroll an Image
23
+ #
24
+ # Example Usage:
25
+ # - require 'kairos'
26
+ # - client = Kairos::Client.new(:app_id => '1234', :app_key => 'abcde1234')
27
+ # - client.enroll(:url => 'https://some.url.com/to_some.jpg', :subject_id => 'gemtest', :gallery_name => 'testgallery')
28
+ def enroll(options={})
29
+ post_to_api(Kairos::Configuration::ENROLL, options)
30
+ end
31
+
32
+ # Recognize an Image
33
+ #
34
+ # Example Usage:
35
+ # - require 'kairos'
36
+ # - client = Kairos::Client.new(:app_id => '1234', :app_key => 'abcde1234')
37
+ # - client.recognize(:url => 'https://some.url.com/to_some_other_image.jpg', :gallery_name => 'testgallery', :threshold => '.2', :max_num_results => '5')
38
+ def recognize(options={})
39
+ post_to_api(Kairos::Configuration::RECOGNIZE, options)
40
+ end
41
+
42
+ # Remove Subject from Gallery
43
+ #
44
+ # Example Usage:
45
+ # - require 'kairos'
46
+ # - client = Kairos::Client.new(:app_id => '1234', :app_key => 'abcde1234')
47
+ # - client.gallery_remove_subject(:gallery_name => 'testgallery', :subject_id => 'gemtest')
48
+ def gallery_remove_subject(options={})
49
+ post_to_api(Kairos::Configuration::GALLERY_REMOVE_SUBJECT, options)
50
+ end
51
+
52
+ # Detect faces in Image
53
+ #
54
+ # Example Usage:
55
+ # - require 'kairos'
56
+ # - client = Kairos::Client.new(:app_id => '1234', :app_key => 'abcde1234')
57
+ # - client.detect(:url => 'https://some.url.com/to_some_other_image.jpg', :selector => 'FULL')
58
+ def detect(options={})
59
+ post_to_api(Kairos::Configuration::DETECT, options)
60
+ end
61
+
62
+ # List all Galleries
63
+ #
64
+ # Example Usage:
65
+ # - require 'kairos'
66
+ # - client = Kairos::Client.new(:app_id => '1234', :app_key => 'abcde1234')
67
+ # - client.gallery_list_all
68
+ def gallery_list_all
69
+ # ToDo: Research why Typhoeus works better than Faraday for this endpoint
70
+ request = Typhoeus::Request.new(
71
+ "#{Kairos::Configuration::GALLERY_LIST_ALL}",
72
+ method: :post,
73
+ headers: { "Content-Type" => "application/x-www-form-urlencoded",
74
+ "app_id" => "#{@app_id}",
75
+ "app_key" => "#{@app_key}" }
76
+ )
77
+ response = request.run
78
+ JSON.parse(response.body) rescue "INVALID_JSON: #{response.body}"
79
+ end
80
+
81
+ # View subjects in Gallery
82
+ #
83
+ # Example Usage:
84
+ # - require 'kairos'
85
+ # - client = Kairos::Client.new(:app_id => '1234', :app_key => 'abcde1234')
86
+ # - client.gallery_view(:gallery_name => 'testgallery')
87
+ def gallery_view(options={})
88
+ post_to_api(Kairos::Configuration::GALLERY_VIEW, options)
89
+ end
90
+
91
+ private
92
+
93
+ def post_to_api(endpoint, options={})
94
+ connection = api_set_connection(endpoint)
95
+ response = options.empty? ? api_post(connection) : api_post(connection, options)
96
+ JSON.parse(response.body) rescue "INVALID_JSON: #{response.body}"
97
+ end
98
+
99
+ def api_set_connection(endpoint)
100
+ Faraday.new(:url => endpoint) do |builder|
101
+ builder.use Faraday::Adapter::NetHttp
102
+ end
103
+ end
104
+
105
+ def api_post(connection, options={})
106
+ connection.post do |request|
107
+ request.headers['Content-Type'] = 'application/x-www-form-urlencoded'
108
+ request.headers['app_id'] = @app_id
109
+ request.headers['app_key'] = @app_key
110
+ request.body = options.empty? ? nil : options.to_json
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,43 @@
1
+ module Kairos
2
+
3
+ module Configuration
4
+ VALID_CONNECTION_KEYS = [:app_id, :app_key].freeze
5
+ VALID_OPTIONS_KEYS = [:url, :subject_id, :gallery_name, :threshold, :max_num_results, :selector].freeze
6
+ VALID_CONFIG_KEYS = VALID_CONNECTION_KEYS + VALID_OPTIONS_KEYS
7
+
8
+ DEFAULT_USER_AGENT = "Kairos API Ruby Gem #{Kairos::VERSION}".freeze
9
+ DEFAULT_APP_ID = nil
10
+ DEFAULT_APP_KEY = nil
11
+
12
+ ENROLL = 'http://api.kairos.io/enroll'
13
+ RECOGNIZE = 'http://api.kairos.io/recognize'
14
+ DETECT = 'http://api.kairos.io/detect'
15
+ GALLERY_LIST_ALL = 'http://api.kairos.io/gallery/list_all'
16
+ GALLERY_VIEW = 'http://api.kairos.io/gallery/view'
17
+ GALLERY_REMOVE_SUBJECT = 'http://api.kairos.io/gallery/remove_subject'
18
+
19
+ # Build accessor methods for every config options so we can do this, for example:
20
+ # Kairos.format = :xml
21
+ attr_accessor *VALID_CONFIG_KEYS
22
+
23
+ # Make sure we have the default values set when we get 'extended'
24
+ def self.extended(base)
25
+ base.reset
26
+ end
27
+
28
+ def reset
29
+ self.app_id = DEFAULT_APP_ID
30
+ self.app_key = DEFAULT_APP_KEY
31
+ end
32
+
33
+ def configure
34
+ yield self
35
+ end
36
+
37
+ # Return the configuration values set in this module
38
+ def options
39
+ Hash[ * VALID_CONFIG_KEYS.map { |key| [key, send(key)] }.flatten ]
40
+ end
41
+ end
42
+
43
+ end
@@ -0,0 +1,3 @@
1
+ module Kairos
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+
3
+ describe Kairos::Client do
4
+
5
+ before do
6
+ @keys = Kairos::Configuration::VALID_CONFIG_KEYS
7
+ end
8
+
9
+ describe 'with module configuration' do
10
+ before do
11
+ Kairos.configure do |config|
12
+ @keys.each do |key|
13
+ config.send("#{key}=", key)
14
+ end
15
+ end
16
+ end
17
+
18
+ after do
19
+ Kairos.reset
20
+ end
21
+
22
+ it "should inherit module configuration" do
23
+ api = Kairos::Client.new
24
+ @keys.each do |key|
25
+ api.send(key).should eq(key)
26
+ end
27
+ end
28
+
29
+ describe 'with class configuration' do
30
+ before do
31
+ @config = {
32
+ :app_id => 'zz',
33
+ :app_key => 'ak',
34
+ :url => 'of',
35
+ :subject_id => 'ep',
36
+ :gallery_name => 'ua',
37
+ :threshold => 'hm',
38
+ :max_num_results => 'bc',
39
+ :selector => 'uy'
40
+ }
41
+ end
42
+
43
+ it 'should override module configuration' do
44
+ api = Kairos::Client.new(@config)
45
+ @keys.each do |key|
46
+ api.send(key).should eq(@config[key])
47
+ end
48
+ end
49
+
50
+ it 'should override module configuration after' do
51
+ api = Kairos::Client.new
52
+
53
+ @config.each do |key, value|
54
+ api.send("#{key}=", value)
55
+ end
56
+
57
+ @keys.each do |key|
58
+ api.send("#{key}").should eq(@config[key])
59
+ end
60
+ end
61
+ end
62
+
63
+ end
64
+
65
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ describe Kairos::Configuration do
4
+
5
+ after do
6
+ Kairos.reset
7
+ end
8
+
9
+ describe '.configure' do
10
+ Kairos::Configuration::VALID_CONFIG_KEYS.each do |key|
11
+ it "should set the #{key}" do
12
+ Kairos.configure do |config|
13
+ config.send("#{key}=", key)
14
+ Kairos.send(key).should eq(key)
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ Kairos::Configuration::VALID_CONNECTION_KEYS.each do |key|
21
+ describe ".#{key}" do
22
+ it 'should return the default value' do
23
+ Kairos.send(key).should eq( Kairos::Configuration.const_get("DEFAULT_#{key.upcase}") )
24
+ end
25
+ end
26
+ end
27
+
28
+ end
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+
3
+ describe Kairos::Client do
4
+
5
+ describe '#detect' do
6
+ before do
7
+ @config = {
8
+ :app_id => 'abc1234',
9
+ :app_key => 'asdfadsfasdfasdfasdf'
10
+ }
11
+ @client = Kairos::Client.new(@config)
12
+ end
13
+
14
+ it 'responds to detect' do
15
+ @client.should respond_to(:detect)
16
+ end
17
+
18
+ context 'with valid credentials' do
19
+ context 'with missing parameters' do
20
+ it 'should not detect faces' do
21
+ VCR.use_cassette('detect_with_missing_parameters') do
22
+ response = @client.detect(:selector => 'FULL')
23
+ response.should eq("INVALID_JSON: [\"errors:\"{\"Errcode\":5001,\"Message\":\"some unknown service error\"}]")
24
+ end
25
+ end
26
+ end
27
+ context 'with image with no faces' do
28
+ it 'should not detect faces' do
29
+ VCR.use_cassette('detect_with_no_faces_in_image') do
30
+ response = @client.detect(:url => 'http://upload.wikimedia.org/wikipedia/commons/thumb/2/23/Seal_of_the_US_Air_Force.svg/356px-Seal_of_the_US_Air_Force.svg.png', :selector => 'FULL')
31
+ response.should eq("INVALID_JSON: [\"errors:\"{\"Errcode\":5002,\"Message\":No face(s) found}]")
32
+ end
33
+ end
34
+ end
35
+ context 'with required parameters' do
36
+ before(:each) do
37
+ VCR.use_cassette('detect') do
38
+ @response = @client.detect(:url => 'http://www.history.com/s3static/video-thumbnails/AETN-History_Prod/24/226/History_First_Combat_By_Black_Pilots_Speech_SF_still_624x352.jpg', :selector => 'FULL')
39
+ end
40
+ end
41
+ describe 'response' do
42
+ it 'detects faces of Tuskegee Airman' do
43
+ @response['images'][0]['status'].should eq("Complete")
44
+ @response['images'][0]['faces'].size.should eq(3)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ end