kairos-api 0.0.1

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.
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