deepstack 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6bd245c6bb369aed6c65f88277a186cd283d396b5eeafa28bc10e854dfbd027c
4
+ data.tar.gz: b428c594d92837534124004c0ff0ef4f0b0c2aad0a2cf40ef4faa69f38d904d3
5
+ SHA512:
6
+ metadata.gz: 1f4d4c306447142dd071a6a4a28ce8f36f2170cf23160401e7cbf1786d9b8124e9c72e1a144c13096b62ad03a361fe4684f0aa8d9fab4aee0b921017ed0fff8c
7
+ data.tar.gz: 2a7c706fbfe815f7faf5ce06294f1eff65c2c9aeec3cdddb865e97348475cf1ee3478b9152444e4a92ae3697eeae3ad4e97a1fd47edff3247578eae52b340953
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Deepstack
4
+ # Custom Model
5
+ module Custom
6
+ #
7
+ # Register a custom inference method for convenience.
8
+ # The custom method is called "identify_<modelname>"
9
+ # Example:
10
+ # deepstack.register_custom_model('license_plate')
11
+ # deepstack.identify_license_plate(image)
12
+ #
13
+ # @param [Array] models a list of one or more custom model names to register
14
+ #
15
+ # @return [<Type>] <description>
16
+ #
17
+ def self.register_model(*models)
18
+ models.flatten.each do |model|
19
+ method_name = 'identify_'.concat model.gsub(/-+/, '_') # convert - to _
20
+ define_method(method_name) do |image, **options|
21
+ custom_inference(model, image, options)
22
+ end
23
+ end
24
+ end
25
+
26
+ #
27
+ # Return predictions using a custom model
28
+ #
29
+ # @param [String] model custom model name
30
+ # @param [Object] image binary data or a File object
31
+ # @param [Hash] options additional fields for Deepstack, e.g. min_confidence: 0.5
32
+ #
33
+ # @return [Array] if successful, an array of Deepstack predictions
34
+ #
35
+ # @return [nil] if error
36
+ #
37
+ def custom_inference(model, image, **options)
38
+ target = "vision/custom/#{model}"
39
+ api_post(target, image, options)
40
+ predictions
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Deepstack
4
+ # APIs related to object detection
5
+ module Detection
6
+ #
7
+ # Perform object detection
8
+ #
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
11
+ #
12
+ # @return [Array] a list of predictions, or nil on error
13
+ #
14
+ def detect_objects(image, **options)
15
+ target = 'vision/detection'
16
+ api_post(target, image, **options)
17
+ predictions
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Deepstack
4
+ # APIs related to face recognition
5
+ module Face
6
+ #
7
+ # Perform face recognition
8
+ #
9
+ # @param [Object] image binary data or a File object
10
+ # @param [Hash] options additional fields for Deepstack, e.g. min_confidence: 0.5
11
+ #
12
+ # @return [Array] if successful, an array of Deepstack predictions
13
+ #
14
+ # @return [nil] if error
15
+ #
16
+ def recognize_faces(image, **options)
17
+ target = 'vision/face/recognize'
18
+ api_post(target, image, **options)
19
+ predictions
20
+ end
21
+
22
+ #
23
+ # Detect faces in an image
24
+ #
25
+ # @param [Object] image binary data or a File object
26
+ # @param [Hash] options additional fields for Deepstack, e.g. min_confidence: 0.5
27
+ #
28
+ # @return [Array] if successful, an array of Deepstack predictions
29
+ #
30
+ def detect_faces(image, **options)
31
+ target = 'vision/face/' # the URL ends with a slash
32
+ api_post(target, image, **options)
33
+ predictions
34
+ end
35
+
36
+ #
37
+ # Get a list of registered faces
38
+ #
39
+ # @return [Array] a list of userids
40
+ #
41
+ def face_list
42
+ target = 'vision/face/list'
43
+ api_post(target)&.dig('faces')
44
+ # {"success"=>true, "faces"=>["face_1", "face_2"], "duration"=>0}
45
+ end
46
+
47
+ #
48
+ # Delete the given list of faces / userids
49
+ #
50
+ # @param [Array] userids a list of userids to delete
51
+ #
52
+ # @return [Hash] A hash of `userid => boolean` that indicates success/failure
53
+ #
54
+ def delete_faces(*userids)
55
+ userids.flatten.compact.to_h { |userid| [userid, delete_face(userid)] }
56
+ end
57
+
58
+ #
59
+ # Delete the given face / userid
60
+ #
61
+ # @param [String] userid to delete
62
+ #
63
+ # @return [Boolean] true when successful
64
+ #
65
+ def delete_face(userid)
66
+ target = 'vision/face/delete'
67
+ api_post(target, userid: userid)
68
+ success?
69
+ end
70
+
71
+ #
72
+ # Register a face
73
+ #
74
+ # @param [String] userid to register
75
+ # @param [Array] images facial image data in binary form or File object
76
+ #
77
+ # @return [Boolean] true when successful
78
+ #
79
+ def register_face(userid, *images)
80
+ target = 'vision/face/register'
81
+ api_post(target, images, userid: userid)
82
+ success?
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Deepstack
4
+ # Scene Recognition
5
+ module Scene
6
+ #
7
+ # Return
8
+ #
9
+ # @param [Object] image binary data or a File object
10
+ # @param [Hash] options additional fields for Deepstack, e.g. min_confidence: 0.5
11
+ #
12
+ # @return [Hash] if successful, Deepstack result hash {'label' => 'scene', 'confidence' => 2.2}
13
+ #
14
+ # @return [nil] if error
15
+ def identify_scene(image, **options)
16
+ target = 'vision/scene'
17
+ api_post(target, image, **options)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,9 @@
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
data/lib/deepstack.rb ADDED
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
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
metadata ADDED
@@ -0,0 +1,52 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: deepstack
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jimmy Tanagra
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-05-09 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email:
15
+ - jcode@tanagra.id.au
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - 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
+ homepage: https://github.com/jimtng/deepstack-ruby
27
+ licenses:
28
+ - EPL-2.0
29
+ metadata:
30
+ homepage_uri: https://github.com/jimtng/deepstack-ruby
31
+ source_code_uri: https://github.com/jimtng/deepstack-ruby
32
+ changelog_uri: https://github.com/jimtng/deepstack-ruby/blob/main/CHANGELOG.md
33
+ post_install_message:
34
+ rdoc_options: []
35
+ require_paths:
36
+ - lib
37
+ required_ruby_version: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: 2.6.0
42
+ required_rubygems_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ requirements: []
48
+ rubygems_version: 3.3.7
49
+ signing_key:
50
+ specification_version: 4
51
+ summary: A Ruby wrapper for Deepstack API
52
+ test_files: []