deepstack 0.0.1 → 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
  SHA256:
3
- metadata.gz: 6bd245c6bb369aed6c65f88277a186cd283d396b5eeafa28bc10e854dfbd027c
4
- data.tar.gz: b428c594d92837534124004c0ff0ef4f0b0c2aad0a2cf40ef4faa69f38d904d3
3
+ metadata.gz: caf4cf801a5a99ff308e5afc06ed19dac86d8348388c519880770d482fd1bb0b
4
+ data.tar.gz: de77bacb1bd1ffb46c4dff277ab16e1195ef423f005ad98394b49cab6e248fa3
5
5
  SHA512:
6
- metadata.gz: 1f4d4c306447142dd071a6a4a28ce8f36f2170cf23160401e7cbf1786d9b8124e9c72e1a144c13096b62ad03a361fe4684f0aa8d9fab4aee0b921017ed0fff8c
7
- data.tar.gz: 2a7c706fbfe815f7faf5ce06294f1eff65c2c9aeec3cdddb865e97348475cf1ee3478b9152444e4a92ae3697eeae3ad4e97a1fd47edff3247578eae52b340953
6
+ metadata.gz: 6836c3bc1e6dc367542c4bd9e3e089ddf2cf3a7e612d6230dfabf3f3a38a4651965eead00bba50dd5916e5a9d8fcc44c624f3743b17165fbda24cff8c9ea7ec8
7
+ data.tar.gz: 5f5c98987f6fae82a67ef8fa57a557aa300bd22da6108a8575eabe6e3ac8d1f301f57caad1f86b533629b503d53db4bb40e101ff630abddce1b2659637e2b177
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Deepstack
3
+ class DeepStack
4
4
  # Custom Model
5
5
  module Custom
6
6
  #
@@ -28,16 +28,15 @@ module Deepstack
28
28
  #
29
29
  # @param [String] model custom model name
30
30
  # @param [Object] image binary data or a File object
31
- # @param [Hash] options additional fields for Deepstack, e.g. min_confidence: 0.5
31
+ # @param [Hash] options additional fields for DeepStack, e.g. min_confidence: 0.5
32
32
  #
33
- # @return [Array] if successful, an array of Deepstack predictions
33
+ # @return [Array] if successful, an array of DeepStack predictions
34
34
  #
35
35
  # @return [nil] if error
36
36
  #
37
37
  def custom_inference(model, image, **options)
38
38
  target = "vision/custom/#{model}"
39
- api_post(target, image, options)
40
- predictions
39
+ api_post(target, image, options)&.dig('predictions')
41
40
  end
42
41
  end
43
42
  end
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'net/http'
4
+ require 'json'
5
+ require_relative 'face'
6
+ require_relative 'detection'
7
+ require_relative 'scene'
8
+ require_relative 'custom'
9
+ require_relative 'version'
10
+
11
+ # DeepStack API
12
+ class DeepStack
13
+ include DeepStack::Face
14
+ include DeepStack::Detection
15
+ include DeepStack::Scene
16
+ include DeepStack::Custom
17
+
18
+ #
19
+ # Create a deepstack object connected to the given URL
20
+ #
21
+ # @param [String] base_url the url to DeepStack's server:port
22
+ # @param [String] api_key an optional API-KEY to use when connecting to DeepStack
23
+ # @param [String] admin_key an optional ADMIN-KEY to use when connecting to DeepStack
24
+ #
25
+ # @example
26
+ # DeepStack.new('http://127.0.0.1:5000')
27
+ #
28
+ def initialize(base_url, api_key: nil, admin_key: nil)
29
+ @base_url = base_url
30
+ @auth = { api_key: api_key, admin_key: admin_key }.select { |_k, v| v } # remove nil values
31
+ @http_mutex = Mutex.new
32
+ end
33
+
34
+ #
35
+ # Make a POST request to DeepStack path target
36
+ #
37
+ # @param [String] path to the DeepStack API URL
38
+ # @param [Array] images zero or more images to post
39
+ # @param [Hash] args additional named fields to post
40
+ #
41
+ # @return [Hash] if successful, the json data returned by DeepStack, nil otherwise
42
+ #
43
+ def api_post(path, *images, **args)
44
+ uri = build_uri(path)
45
+ args = @auth.merge(args)
46
+
47
+ result = nil
48
+ 10.times do
49
+ result = images ? post_files(uri, images.flatten, **args) : post(uri, args)
50
+ break unless result.is_a?(Net::HTTPRedirection)
51
+
52
+ uri.path = result['location']
53
+ end
54
+ raise Net::HTTPClientException, 'Too many redirections' if result.is_a?(Net::HTTPRedirection)
55
+
56
+ process_result(result)
57
+ end
58
+
59
+ #
60
+ # Close the HTTP connection to DeepStack server
61
+ #
62
+ def close
63
+ @http_mutex.synchronize do
64
+ @http&.finish
65
+ @http = nil
66
+ end
67
+ end
68
+
69
+ private
70
+
71
+ def build_uri(path)
72
+ URI.join(@base_url, '/v1/', path)
73
+ end
74
+
75
+ def post(uri, **args)
76
+ Net::HTTP.post_form(uri, args)
77
+ end
78
+
79
+ def post_files(uri, *images, **args)
80
+ form_data = combine_images_and_args(images.flatten, **args)
81
+ req = Net::HTTP::Post.new(uri)
82
+ req.set_form(form_data, 'multipart/form-data')
83
+ @http_mutex.synchronize do
84
+ @http ||= Net::HTTP.start(uri.hostname, uri.port)
85
+ @http.request(req)
86
+ end
87
+ end
88
+
89
+ def combine_images_and_args(*images, **args)
90
+ stringify_keys(args).concat(image_form_data(images.flatten))
91
+ end
92
+
93
+ def stringify_keys(hash)
94
+ hash.map { |k, v| [k.to_s, v] }
95
+ end
96
+
97
+ #
98
+ # Return an array of image entries for form data.
99
+ # The field name is 'image' for a single image
100
+ # For multiple images, the field names will be 'image1', 'image2', ...
101
+ #
102
+ # @param [Array<Object>] images an array of raw image data or a File object
103
+ #
104
+ # @return [Array] the image entries for set_form
105
+ #
106
+ def image_form_data(*images)
107
+ images = images.flatten
108
+ return [image_entry('image', images.first)] if images.length == 1
109
+
110
+ images.map.with_index(1) { |image, i| image_entry("image#{i}", image) }
111
+ end
112
+
113
+ def image_entry(name, image)
114
+ [name, image].tap { |result| result << { filename: "#{name}.jpg" } unless image.instance_of? File }
115
+ end
116
+
117
+ def process_result(result)
118
+ result.is_a?(Net::HTTPSuccess) ? JSON.parse(result.body) : nil
119
+ end
120
+ end
@@ -1,20 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Deepstack
3
+ class DeepStack
4
4
  # APIs related to object detection
5
5
  module Detection
6
6
  #
7
7
  # Perform object detection
8
8
  #
9
9
  # @param [Object] image raw image data or a File object of an image file
10
- # @param [Hash] options additional fields for Deepstack, e.g. min_confidence: 0.5
10
+ # @param [Hash] options additional fields for DeepStack, e.g. min_confidence: 0.5
11
11
  #
12
12
  # @return [Array] a list of predictions, or nil on error
13
13
  #
14
14
  def detect_objects(image, **options)
15
15
  target = 'vision/detection'
16
- api_post(target, image, **options)
17
- predictions
16
+ api_post(target, image, **options)&.dig('predictions')
18
17
  end
19
18
  end
20
19
  end
@@ -1,36 +1,34 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Deepstack
3
+ class DeepStack
4
4
  # APIs related to face recognition
5
5
  module Face
6
6
  #
7
7
  # Perform face recognition
8
8
  #
9
9
  # @param [Object] image binary data or a File object
10
- # @param [Hash] options additional fields for Deepstack, e.g. min_confidence: 0.5
10
+ # @param [Hash] options additional fields for DeepStack, e.g. min_confidence: 0.5
11
11
  #
12
- # @return [Array] if successful, an array of Deepstack predictions
12
+ # @return [Array] if successful, an array of DeepStack predictions
13
13
  #
14
14
  # @return [nil] if error
15
15
  #
16
16
  def recognize_faces(image, **options)
17
17
  target = 'vision/face/recognize'
18
- api_post(target, image, **options)
19
- predictions
18
+ api_post(target, image, **options)&.dig('predictions')
20
19
  end
21
20
 
22
21
  #
23
22
  # Detect faces in an image
24
23
  #
25
24
  # @param [Object] image binary data or a File object
26
- # @param [Hash] options additional fields for Deepstack, e.g. min_confidence: 0.5
25
+ # @param [Hash] options additional fields for DeepStack, e.g. min_confidence: 0.5
27
26
  #
28
- # @return [Array] if successful, an array of Deepstack predictions
27
+ # @return [Array] if successful, an array of DeepStack predictions
29
28
  #
30
29
  def detect_faces(image, **options)
31
30
  target = 'vision/face/' # the URL ends with a slash
32
- api_post(target, image, **options)
33
- predictions
31
+ api_post(target, image, **options)&.dig('predictions')
34
32
  end
35
33
 
36
34
  #
@@ -64,8 +62,7 @@ module Deepstack
64
62
  #
65
63
  def delete_face(userid)
66
64
  target = 'vision/face/delete'
67
- api_post(target, userid: userid)
68
- success?
65
+ api_post(target, userid: userid)&.dig('success') == true
69
66
  end
70
67
 
71
68
  #
@@ -78,8 +75,7 @@ module Deepstack
78
75
  #
79
76
  def register_face(userid, *images)
80
77
  target = 'vision/face/register'
81
- api_post(target, images, userid: userid)
82
- success?
78
+ api_post(target, images, userid: userid)&.dig('success') == true
83
79
  end
84
80
  end
85
81
  end
@@ -1,15 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Deepstack
3
+ class DeepStack
4
4
  # Scene Recognition
5
5
  module Scene
6
6
  #
7
7
  # Return
8
8
  #
9
9
  # @param [Object] image binary data or a File object
10
- # @param [Hash] options additional fields for Deepstack, e.g. min_confidence: 0.5
10
+ # @param [Hash] options additional fields for DeepStack, e.g. min_confidence: 0.5
11
11
  #
12
- # @return [Hash] if successful, Deepstack result hash {'label' => 'scene', 'confidence' => 2.2}
12
+ # @return [Hash] if successful, DeepStack result hash {'label' => 'scene', 'confidence' => 2.2}
13
13
  #
14
14
  # @return [nil] if error
15
15
  def identify_scene(image, **options)
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Holds project version constant
5
+ #
6
+ class DeepStack
7
+ # @return [String] Version of DeepStack helper libraries
8
+ VERSION = '1.2.0'
9
+ end
data/lib/deepstack.rb CHANGED
@@ -1,111 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'pp'
4
- require 'net/http'
5
- require 'json'
6
- require_relative 'deepstack/face'
7
- require_relative 'deepstack/detection'
8
- require_relative 'deepstack/scene'
9
- require_relative 'deepstack/custom'
10
- require_relative 'deepstack/version'
11
-
12
- module Deepstack
13
- # Deepstack API
14
- class API
15
- include Deepstack::Face
16
- include Deepstack::Detection
17
- include Deepstack::Scene
18
- include Deepstack::Custom
19
-
20
- attr_reader :duration, :predictions, :success
21
-
22
- # Create a deepstack object connected to the given URL
23
- def initialize(base_url)
24
- @base_url = base_url
25
- end
26
-
27
- #
28
- # The result of the last call
29
- #
30
- # @return [Boolean] true if the last call was successful
31
- #
32
- def success?
33
- @success == true
34
- end
35
-
36
- #
37
- # Make a POST request to Deepstack path target
38
- #
39
- # @param [String] path to the Deepstack API URL
40
- # @param [Array] images zero or more images to post
41
- # @param [Hash] args additional named fields to post
42
- #
43
- # @return [Hash] if successful, the json data returned by Deepstack, nil otherwise
44
- #
45
- def api_post(path, *images, **args)
46
- uri = build_uri(path)
47
-
48
- result = nil
49
- 10.times do
50
- result = images ? post_files(uri, images.flatten, **args) : post(uri, args)
51
- break unless result.is_a?(Net::HTTPRedirection)
52
-
53
- uri.path = result['location']
54
- end
55
- raise Net::HTTPClientException, 'Too many redirections' if result.is_a?(Net::HTTPRedirection)
56
-
57
- process_result(result)
58
- end
59
-
60
- private
61
-
62
- def build_uri(path)
63
- URI.join(@base_url, '/v1/', path)
64
- end
65
-
66
- def post(uri, **args)
67
- Net::HTTP.post_form(uri, args)
68
- end
69
-
70
- def post_files(uri, *images, **args)
71
- form_data = combine_images_and_args(images.flatten, **args)
72
- req = Net::HTTP::Post.new(uri)
73
- req.set_form(form_data, 'multipart/form-data')
74
- Net::HTTP.start(uri.hostname, uri.port) { |http| http.request(req) }
75
- end
76
-
77
- def combine_images_and_args(*images, **args)
78
- stringify_keys(args).concat(image_form_data(images.flatten))
79
- end
80
-
81
- def stringify_keys(hash)
82
- hash.map { |k, v| [k.to_s, v] }
83
- end
84
-
85
- #
86
- # Return an array of image entries for form data.
87
- # The field name is 'image' for a single image
88
- # For multiple images, the field names will be 'image1', 'image2', ...
89
- #
90
- # @param [Array<Object>] images an array of raw image data or a File object
91
- #
92
- # @return [Array] the image entries for set_form
93
- #
94
- def image_form_data(*images)
95
- images = images.flatten
96
- return [image_entry('image', images.first)] if images.length == 1
97
-
98
- images.map.with_index(1) { |image, i| image_entry("image#{i}", image) }
99
- end
100
-
101
- def image_entry(name, image)
102
- [name, image].tap { |result| result << { filename: "#{name}.jpg" } unless image.instance_of? File }
103
- end
104
-
105
- def process_result(result)
106
- @result = result.is_a?(Net::HTTPSuccess) ? JSON.parse(result.body) : nil
107
- %w[success duration predictions].each { |attrib| instance_variable_set("@#{attrib}", @result&.dig(attrib)) }
108
- @result
109
- end
110
- end
111
- end
3
+ require_relative 'deep_stack/deep_stack'
metadata CHANGED
@@ -1,36 +1,38 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: deepstack
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jimmy Tanagra
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-05-09 00:00:00.000000000 Z
11
+ date: 2022-05-11 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description:
13
+ description:
14
14
  email:
15
15
  - jcode@tanagra.id.au
16
16
  executables: []
17
17
  extensions: []
18
18
  extra_rdoc_files: []
19
19
  files:
20
+ - lib/deep_stack/custom.rb
21
+ - lib/deep_stack/deep_stack.rb
22
+ - lib/deep_stack/detection.rb
23
+ - lib/deep_stack/face.rb
24
+ - lib/deep_stack/scene.rb
25
+ - lib/deep_stack/version.rb
20
26
  - lib/deepstack.rb
21
- - lib/deepstack/custom.rb
22
- - lib/deepstack/detection.rb
23
- - lib/deepstack/face.rb
24
- - lib/deepstack/scene.rb
25
- - lib/deepstack/version.rb
26
27
  homepage: https://github.com/jimtng/deepstack-ruby
27
28
  licenses:
28
29
  - EPL-2.0
29
30
  metadata:
30
31
  homepage_uri: https://github.com/jimtng/deepstack-ruby
31
32
  source_code_uri: https://github.com/jimtng/deepstack-ruby
33
+ documentation_uri: https://rubydoc.info/gems/deepstack
32
34
  changelog_uri: https://github.com/jimtng/deepstack-ruby/blob/main/CHANGELOG.md
33
- post_install_message:
35
+ post_install_message:
34
36
  rdoc_options: []
35
37
  require_paths:
36
38
  - lib
@@ -45,8 +47,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
45
47
  - !ruby/object:Gem::Version
46
48
  version: '0'
47
49
  requirements: []
48
- rubygems_version: 3.3.7
49
- signing_key:
50
+ rubygems_version: 3.0.3.1
51
+ signing_key:
50
52
  specification_version: 4
51
- summary: A Ruby wrapper for Deepstack API
53
+ summary: A Ruby wrapper for DeepStack API
52
54
  test_files: []
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- #
4
- # Holds project version constant
5
- #
6
- module Deepstack
7
- # @return [String] Version of Deepstack helper libraries
8
- VERSION = '0.0.1'
9
- end