deepstack 0.0.1 → 1.2.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.
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