clarinet 0.5.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 +7 -0
- data/.gitignore +89 -0
- data/.rspec +1 -0
- data/.rubocop.yml +2299 -0
- data/.travis.yml +6 -0
- data/Gemfile +20 -0
- data/LICENSE +15 -0
- data/README.md +29 -0
- data/Rakefile +12 -0
- data/clarinet.gemspec +19 -0
- data/lib/clarinet.rb +17 -0
- data/lib/clarinet/app.rb +28 -0
- data/lib/clarinet/client.rb +161 -0
- data/lib/clarinet/concept.rb +22 -0
- data/lib/clarinet/concepts.rb +47 -0
- data/lib/clarinet/error/error.rb +29 -0
- data/lib/clarinet/input.rb +63 -0
- data/lib/clarinet/inputs.rb +108 -0
- data/lib/clarinet/model.rb +133 -0
- data/lib/clarinet/models.rb +106 -0
- data/lib/clarinet/status.rb +13 -0
- data/lib/clarinet/utils.rb +102 -0
- data/lib/clarinet/version.rb +5 -0
- data/spec/app_spec.rb +12 -0
- data/spec/fixtures/model-predict-default.txt +11 -0
- data/spec/fixtures/models-get.txt +11 -0
- data/spec/fixtures/models-list.txt +11 -0
- data/spec/fixtures/search-general-concept.txt +11 -0
- data/spec/model_spec.rb +57 -0
- data/spec/models_spec.rb +106 -0
- data/spec/spec_helper.rb +109 -0
- metadata +101 -0
data/.travis.yml
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# A sample Gemfile
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
gemspec
|
6
|
+
|
7
|
+
group :development do
|
8
|
+
gem 'yard'
|
9
|
+
end
|
10
|
+
|
11
|
+
group :development, :test do
|
12
|
+
gem 'rake'
|
13
|
+
end
|
14
|
+
|
15
|
+
group :test do
|
16
|
+
gem 'mocha', '1.2.1'
|
17
|
+
gem 'rspec', '3.6.0'
|
18
|
+
gem 'simplecov', '0.15.0', require: false
|
19
|
+
gem 'webmock', '3.0.1'
|
20
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
ISC License
|
2
|
+
|
3
|
+
Copyright (c) 2016-, Jaakko Rinta-Filppula
|
4
|
+
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
8
|
+
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
10
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
11
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
12
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
13
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
14
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
15
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
Clarinet [](https://travis-ci.org/tophattom/clarinet)
|
2
|
+
===
|
3
|
+
|
4
|
+
Ruby client for [Clarifai](https://clarifai.com) API v2.
|
5
|
+
|
6
|
+
Clarinet matches Clarifai's official JavaScript SDK almost 1:1.
|
7
|
+
Method names are mostly the same expect in `snake_case` as opposed
|
8
|
+
to `camelCase` in the JS library.
|
9
|
+
|
10
|
+
## Dependencies
|
11
|
+
|
12
|
+
* `addressable`
|
13
|
+
* `httparty`
|
14
|
+
|
15
|
+
## Install
|
16
|
+
|
17
|
+
## Usage
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
# Your client ID and secret
|
21
|
+
api_key = '...'
|
22
|
+
|
23
|
+
# Initialize
|
24
|
+
client = Clarinet::App.new api_key
|
25
|
+
|
26
|
+
# Get predictions for image with URL.
|
27
|
+
# Response keys are symbolized.
|
28
|
+
outputs = client.models.predict(Clarinet::Model::GENERAL, 'https://samples.clarifai.com/metro-north.jpg')
|
29
|
+
```
|
data/Rakefile
ADDED
data/clarinet.gemspec
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lib/clarinet/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'clarinet'
|
7
|
+
s.version = Clarinet::VERSION
|
8
|
+
s.summary = 'Clarifai API client'
|
9
|
+
s.description = 'Simple client to interface with the Clarifai API v2'
|
10
|
+
s.authors = ['Jaakko Rinta-Filppula']
|
11
|
+
s.email = 'jaakko.rf@gmail.com'
|
12
|
+
s.homepage = 'https://github.com/tophattom/clarinet'
|
13
|
+
s.license = 'ISC'
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
|
17
|
+
s.add_dependency 'httparty', ['~> 0.14']
|
18
|
+
s.add_dependency 'addressable', ['~> 2.5']
|
19
|
+
end
|
data/lib/clarinet.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'clarinet/status'
|
4
|
+
require 'clarinet/error/error'
|
5
|
+
require 'clarinet/utils'
|
6
|
+
|
7
|
+
require 'clarinet/client'
|
8
|
+
|
9
|
+
require 'clarinet/concept'
|
10
|
+
require 'clarinet/concepts'
|
11
|
+
require 'clarinet/input'
|
12
|
+
require 'clarinet/inputs'
|
13
|
+
|
14
|
+
require 'clarinet/model'
|
15
|
+
require 'clarinet/models'
|
16
|
+
|
17
|
+
require 'clarinet/app'
|
data/lib/clarinet/app.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Clarinet
|
4
|
+
class App
|
5
|
+
|
6
|
+
# @!visibility private
|
7
|
+
attr_reader :client
|
8
|
+
|
9
|
+
# @return [Clarinet::Concepts]
|
10
|
+
attr_reader :concepts
|
11
|
+
|
12
|
+
# @return [Clarinet::Inputs]
|
13
|
+
attr_reader :inputs
|
14
|
+
|
15
|
+
# @return [Clarinet::Models]
|
16
|
+
attr_reader :models
|
17
|
+
|
18
|
+
# @param api_key [String] Clarifai API key
|
19
|
+
def initialize(api_key)
|
20
|
+
@client = Clarinet::Client.new api_key
|
21
|
+
|
22
|
+
@concepts = Clarinet::Concepts.new self
|
23
|
+
@inputs = Clarinet::Inputs.new self
|
24
|
+
@models = Clarinet::Models.new self
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'httparty'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
module Clarinet
|
7
|
+
# @!visibility private
|
8
|
+
class Client
|
9
|
+
include HTTParty
|
10
|
+
|
11
|
+
base_uri 'https://api.clarifai.com/v2'
|
12
|
+
format :plain
|
13
|
+
headers 'Content-Type' => 'application/json'
|
14
|
+
|
15
|
+
def initialize(api_key)
|
16
|
+
@auth_headers = {
|
17
|
+
'Authorization' => "Key #{api_key}"
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
def models(options = {})
|
22
|
+
with_response_parsing do
|
23
|
+
self.class.get '/models', headers: @auth_headers, query: options
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def model(id)
|
28
|
+
with_response_parsing do
|
29
|
+
self.class.get "/models/#{id}", headers: @auth_headers
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def model_output_info(id)
|
34
|
+
with_response_parsing do
|
35
|
+
self.class.get "/models/#{id}/output_info", headers: @auth_headers
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def model_train(id)
|
40
|
+
with_response_parsing do
|
41
|
+
self.class.post "/models/#{id}/versions", header: @auth_headers
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def model_versions(id, options = {})
|
46
|
+
with_response_parsing do
|
47
|
+
self.class.get "/models/#{id}/versions", headers: @auth_headers, query: options
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def models_search(query)
|
52
|
+
body = { model_query: query }
|
53
|
+
|
54
|
+
with_response_parsing do
|
55
|
+
self.class.post '/models/searches', headers: @auth_headers, body: body.to_json
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def models_update(data)
|
60
|
+
with_response_parsing do
|
61
|
+
self.class.patch '/models', headers: @auth_headers, body: data.to_json
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def outputs(model_id, inputs, config = {})
|
66
|
+
body = { inputs: inputs }
|
67
|
+
body[:model] = { output_info: { output_config: config } } unless config.empty?
|
68
|
+
|
69
|
+
with_response_parsing do
|
70
|
+
self.class.post "/models/#{model_id}/outputs", headers: @auth_headers, body: body.to_json
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def concepts(options = {})
|
75
|
+
with_response_parsing do
|
76
|
+
self.class.get '/concepts', headers: @auth_headers, query: options
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def concept(id)
|
81
|
+
with_response_parsing do
|
82
|
+
self.class.get "/concepts/#{id}", headers: @auth_headers
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def concepts_search(query)
|
87
|
+
body = { concept_query: query }
|
88
|
+
|
89
|
+
with_response_parsing do
|
90
|
+
self.class.post '/concepts/searches', headers: @auth_headers, body: body.to_json
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def inputs_create(concepts)
|
95
|
+
body = { concepts: concepts }
|
96
|
+
|
97
|
+
with_response_parsing do
|
98
|
+
self.class.post '/concepts', headers: @auth_headers, body: body.to_json
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def inputs(options = {})
|
103
|
+
with_response_parsing do
|
104
|
+
self.class.get '/inputs', headers: @auth_headers, query: options
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def inputs_create(inputs)
|
109
|
+
body = { inputs: inputs }
|
110
|
+
|
111
|
+
with_response_parsing do
|
112
|
+
self.class.post '/inputs', headers: @auth_headers, body: body.to_json
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def input_delete(id)
|
117
|
+
with_response_parsing do
|
118
|
+
self.class.delete "/inputs/#{id}", headers: @auth_headers
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def inputs_delete(ids)
|
123
|
+
body = { ids: ids }
|
124
|
+
|
125
|
+
with_response_parsing do
|
126
|
+
self.class.delete '/inputs', headers: @auth_headers, body: body.to_json
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def inputs_delete_all
|
131
|
+
body = { delete_all: true }
|
132
|
+
|
133
|
+
with_response_parsing do
|
134
|
+
self.class.delete '/inputs', headers: @auth_headers, body: body.to_json
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def inputs_status
|
139
|
+
with_response_parsing do
|
140
|
+
self.class.get '/inputs/status', headers: @auth_headers
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def inputs_update(data)
|
145
|
+
with_response_parsing do
|
146
|
+
self.class.patch '/inputs', headers: @auth_headers, body: data.to_json
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
|
151
|
+
private
|
152
|
+
|
153
|
+
def with_response_parsing(&block)
|
154
|
+
response = yield
|
155
|
+
data = JSON.parse response.parsed_response, symbolize_names: true
|
156
|
+
Clarinet::Utils.check_response_status data[:status]
|
157
|
+
data
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Clarinet
|
2
|
+
class Concept
|
3
|
+
|
4
|
+
attr_reader :id
|
5
|
+
attr_reader :name
|
6
|
+
attr_reader :app_id
|
7
|
+
attr_reader :value
|
8
|
+
attr_reader :created_at
|
9
|
+
attr_reader :raw_data
|
10
|
+
|
11
|
+
def initialize(raw_data = {})
|
12
|
+
@raw_data = raw_data
|
13
|
+
|
14
|
+
@id = raw_data[:id]
|
15
|
+
@name = raw_data[:name]
|
16
|
+
@created_at = raw_data[:created_at]
|
17
|
+
@app_id = raw_data[:app_id]
|
18
|
+
@value = raw_data[:value]
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Clarinet
|
4
|
+
class Concepts
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
delegate [:[], :each, :map, :find, :select, :reject] => :@concepts
|
8
|
+
|
9
|
+
def initialize(app, raw_data = [])
|
10
|
+
@app = app
|
11
|
+
@raw_data = raw_data
|
12
|
+
|
13
|
+
@concepts = raw_data.map do |concept_data|
|
14
|
+
Clarinet::Concept.new concept_data
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def create(concepts)
|
19
|
+
concepts = [concepts] unless concepts.is_a? Array
|
20
|
+
concepts = concepts.map { |concept| format_concept(concept) }
|
21
|
+
|
22
|
+
data = @app.client.concepts.create concepts
|
23
|
+
Clarinet::Concepts.new @app, data[:concepts]
|
24
|
+
end
|
25
|
+
|
26
|
+
def list(options = { page: 1, per_page: 20 })
|
27
|
+
data = @app.client.concepts options
|
28
|
+
Clarinet::Concepts.new @app, data[:concepts]
|
29
|
+
end
|
30
|
+
|
31
|
+
def get(id)
|
32
|
+
data = @app.client.concept id
|
33
|
+
Clarinet::Concept.new data[:concept]
|
34
|
+
end
|
35
|
+
|
36
|
+
def search(name, language = nil)
|
37
|
+
query = {
|
38
|
+
name: name,
|
39
|
+
language: language
|
40
|
+
}
|
41
|
+
|
42
|
+
data = @app.client.concepts_search query
|
43
|
+
Clarinet::Concepts.new @app, data[:concepts]
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Clarinet
|
2
|
+
module Error
|
3
|
+
class ApiError < StandardError
|
4
|
+
attr_accessor :code
|
5
|
+
attr_accessor :description
|
6
|
+
attr_accessor :details
|
7
|
+
end
|
8
|
+
|
9
|
+
class InvalidAuthTokenError < ApiError
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
class ApiKeyNotFoundError < ApiError
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
class BadRequestFormatError < ApiError
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
class InvalidRequestError < ApiError
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
class ImageDecodingError < ApiError
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Clarinet
|
4
|
+
class Input
|
5
|
+
|
6
|
+
attr_reader :id
|
7
|
+
attr_reader :created_at
|
8
|
+
attr_reader :image_url
|
9
|
+
attr_reader :concepts
|
10
|
+
attr_reader :score
|
11
|
+
attr_reader :metadata
|
12
|
+
attr_reader :raw_data
|
13
|
+
|
14
|
+
def initialize(app, raw_data)
|
15
|
+
@app = app
|
16
|
+
|
17
|
+
@id = raw_data[:id]
|
18
|
+
@created_at = raw_data[:created_at]
|
19
|
+
@image_url = raw_data[:data][:image_url]
|
20
|
+
|
21
|
+
@concepts = Clarinet::Concepts.new app, raw_data[:data][:concepts]
|
22
|
+
|
23
|
+
@score = raw_data[:score]
|
24
|
+
@metadata = raw_data[:data][:metadata]
|
25
|
+
|
26
|
+
@raw_data = raw_data
|
27
|
+
end
|
28
|
+
|
29
|
+
def merge_concepts(concepts, metadata = nil)
|
30
|
+
update 'merge', concepts: concepts, metadata: metadata
|
31
|
+
end
|
32
|
+
|
33
|
+
def delete_concepts(concepts, metadata = nil)
|
34
|
+
update 'remove', concepts: concepts, metadata: metadata
|
35
|
+
end
|
36
|
+
|
37
|
+
def overwrite_concepts(concepts, metadata = nil)
|
38
|
+
update 'overwrite', concepts: concepts, metadata: metadata
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def update(action, concepts: [], metadata: nil)
|
44
|
+
input_data = {}
|
45
|
+
input_data[:concepts] = concepts unless concepts.empty?
|
46
|
+
input_data[:metadata] = metadata unless metadata.nil?
|
47
|
+
|
48
|
+
data = {
|
49
|
+
action: action,
|
50
|
+
inputs: [
|
51
|
+
{
|
52
|
+
id: id,
|
53
|
+
data: input_data
|
54
|
+
}
|
55
|
+
]
|
56
|
+
}
|
57
|
+
|
58
|
+
response_data = @app.client.inputs_update data
|
59
|
+
Clarinet::Input.new response_data[:input]
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|