clarification 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -1
- data/README.md +55 -14
- data/bin/console +28 -3
- data/clarification.gemspec +1 -1
- data/lib/clarification.rb +6 -0
- data/lib/clarification/client.rb +9 -4
- data/lib/clarification/concept.rb +4 -0
- data/lib/clarification/configuration.rb +2 -2
- data/lib/clarification/end_points.rb +2 -1
- data/lib/clarification/enrich.rb +0 -1
- data/lib/clarification/hit.rb +4 -0
- data/lib/clarification/objectifier.rb +50 -4
- data/lib/clarification/requester.rb +15 -3
- data/lib/clarification/requester/search_requester.rb +70 -0
- data/lib/clarification/response.rb +4 -0
- data/lib/clarification/response/search_response.rb +27 -0
- data/lib/clarification/search.rb +29 -0
- data/lib/clarification/version.rb +1 -1
- metadata +9 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 14dba1413119dc7a3ad0e944dfcbd825b40eb326
|
4
|
+
data.tar.gz: 205ad9143ccb00f1b5f9777383358a2b9abd0870
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 31c796e17b2e9942b4f85340f979a7c08d268b6615b74ea234aca305cefc71e09810790f9d138f30ef72ba9d7e4742d3400049fb27e0cb83dbdbba8b5c047b0a
|
7
|
+
data.tar.gz: a93bab9d28a78f65105dd7efe3286b8db22843c16781d0db017a6932fe8dca53a0f609949761cc08a6e107ed00f455c7a96a7079663dc366cce4d12d94f3f3df
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -2,10 +2,13 @@
|
|
2
2
|
[![Build Status](https://travis-ci.org/nicholalexander/clarification.svg?branch=master)](https://travis-ci.org/nicholalexander/clarification)
|
3
3
|
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/cb0dd6cce7ec48a191696780951c5efe)](https://www.codacy.com/app/nicholalexander/clarification?utm_source=github.com&utm_medium=referral&utm_content=nicholalexander/clarification&utm_campaign=Badge_Grade)
|
4
4
|
|
5
|
-
|
6
5
|
# Clarification
|
7
6
|
|
8
|
-
|
7
|
+
An unofficial Ruby wrapper for the [Clarifai](http://clarifai.com) API. This currently uses v2 of the API and was partially created because other Ruby gems are using v1 which is being depricated in late 2017.
|
8
|
+
|
9
|
+
Clarifai is an awesome service and hopefully this gem makes it easier to use it and to use AI image tagging in your Ruby apps. Please let me know if there's something you'd like to see but don't or if you see something you wish you didn't. Thanks!
|
10
|
+
|
11
|
+
This gem is currently in development and there is lots likely to change so please be aware!
|
9
12
|
|
10
13
|
## Installation
|
11
14
|
|
@@ -25,18 +28,20 @@ Or install it yourself as:
|
|
25
28
|
|
26
29
|
## Configuration
|
27
30
|
|
28
|
-
Configure the gem as you would normally.
|
31
|
+
Configure the gem as you would normally configure a wonderful happy gem.
|
29
32
|
|
30
33
|
```ruby
|
31
34
|
Clarification.configure do |config|
|
32
35
|
config.api_key = 'a_big_secret_you_got_from_clarifai'
|
33
|
-
config.
|
36
|
+
config.default_public_models = [:food, :general]
|
34
37
|
end
|
35
38
|
```
|
36
39
|
|
37
40
|
This should also work nicely inside a rails initializer.
|
38
41
|
|
39
|
-
Each endpoint initialized in your configuration will be called.
|
42
|
+
**Each endpoint initialized in your configuration will be called by default from the client. So any predictions using a client configured with `:food` and `:general` will make two API requests.**
|
43
|
+
|
44
|
+
This will change when [Workflow](https://clarifai.com/developer/guide/workflow#workflow) is implemented in the gem.
|
40
45
|
|
41
46
|
## Usage
|
42
47
|
|
@@ -47,7 +52,7 @@ response = client.predict(some_public_url_of_an_image)
|
|
47
52
|
|
48
53
|
### Prediction
|
49
54
|
|
50
|
-
The response object returned from the prediction is a hash containing a nicely parsed result for each of the models called. In
|
55
|
+
The response object returned from the prediction is a hash containing a nicely parsed result for each of the models called. In the above configuration example we have two models. So we will have response[:food] and response[:general] after asking for a prediction. Each of those model results have an object which has three pieces of relevant information: status, concepts, and response_json.
|
51
56
|
|
52
57
|
Thusly you can do things like this:
|
53
58
|
|
@@ -59,16 +64,18 @@ response[:food].concepts.each do |concept|
|
|
59
64
|
end
|
60
65
|
```
|
61
66
|
|
62
|
-
```ruby
|
63
|
-
response[:general].response_json
|
64
|
-
```
|
65
|
-
|
66
67
|
```ruby
|
67
68
|
if response[:food].status.code == 10000
|
68
69
|
puts response[:food].status.description
|
69
70
|
end
|
70
71
|
```
|
71
72
|
|
73
|
+
If you want the actual api response, it's here:
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
response[:general].response_json
|
77
|
+
```
|
78
|
+
|
72
79
|
All the objects are OpenStructs currently, but I suspect this will change shortly.
|
73
80
|
|
74
81
|
As a convenience, the client also maintains the parsed response in the last_response variable.
|
@@ -78,6 +85,37 @@ client.predict(some_public_url_of_an_image)
|
|
78
85
|
client.last_response #=> {:food => Objectifier...}
|
79
86
|
```
|
80
87
|
|
88
|
+
### Search
|
89
|
+
|
90
|
+
The client has a search object which can be used to index images with the Clarifai application identified by the API key.
|
91
|
+
|
92
|
+
Thusly you can do like this:
|
93
|
+
|
94
|
+
```ruby
|
95
|
+
image_array = [ url_to_picture_of_kitten, url_to_picture_of_pizza, url_to_picture_of_drake]
|
96
|
+
client.search.index_images(image_array)
|
97
|
+
```
|
98
|
+
|
99
|
+
Once you have your images indexed, you can go and search them by concepts that might be in your picture as identified by Clarifai's general prediction model.
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
results = client.search.by_concept('cat')
|
103
|
+
results.hits.each do |hit|
|
104
|
+
puts hit.url if hit.score > .90
|
105
|
+
end
|
106
|
+
```
|
107
|
+
|
108
|
+
The search client also saves the last search and searched concept as a matter of convenience.
|
109
|
+
|
110
|
+
```ruby
|
111
|
+
client.search.last_search.hits.count
|
112
|
+
client.search.last_search.concept
|
113
|
+
```
|
114
|
+
|
115
|
+
Go and do likewise.
|
116
|
+
|
117
|
+
### Train
|
118
|
+
|
81
119
|
## TODO's
|
82
120
|
|
83
121
|
Lots and lots of things. Amongst them:
|
@@ -86,6 +124,8 @@ Lots and lots of things. Amongst them:
|
|
86
124
|
* error handling
|
87
125
|
* predict multiple images per call
|
88
126
|
* predict video
|
127
|
+
* better testing.
|
128
|
+
* documentation
|
89
129
|
* use workflows
|
90
130
|
* searching
|
91
131
|
* training custom models
|
@@ -94,15 +134,16 @@ Lots and lots of things. Amongst them:
|
|
94
134
|
|
95
135
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
96
136
|
|
97
|
-
|
137
|
+
The repo intentionally includes an api key in bin/console to make experimenting easy and quick. If you plan on making a bunch of requests, you can easily sign up for [your own free key](https://clarifai.com/signup/).
|
98
138
|
|
99
139
|
## Contributing
|
100
140
|
|
101
141
|
Bug reports and pull requests are welcome on GitHub at https://github.com/nicholalexander/clarification. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
102
142
|
|
103
|
-
|
104
|
-
https://
|
105
|
-
|
143
|
+
You can also see various code reporting / CI info here:
|
144
|
+
[travis ci](https://travis-ci.org/nicholalexander/clarification)
|
145
|
+
[codacy](https://www.codacy.com/app/nicholalexander/clarification)
|
146
|
+
[code climate](https://codeclimate.com/github/nicholalexander/clarification)
|
106
147
|
|
107
148
|
## License
|
108
149
|
|
data/bin/console
CHANGED
@@ -2,19 +2,44 @@
|
|
2
2
|
|
3
3
|
require "bundler/setup"
|
4
4
|
require "clarification"
|
5
|
+
require "yaml"
|
5
6
|
|
6
7
|
# You can add fixtures and/or initialization code here to make experimenting
|
7
8
|
# with your gem easier. You can also use a different console, if you like.
|
8
9
|
|
9
10
|
Clarification.configure do |config|
|
10
11
|
config.api_key = 'f7cc628178994e16b2470ae739ef927a'
|
11
|
-
config.
|
12
|
+
config.default_public_models = [:food, :general]
|
12
13
|
end
|
13
14
|
|
14
|
-
@
|
15
|
+
@images = YAML.load_file("spec/support/images.yml")
|
16
|
+
|
17
|
+
@urls = [ @images[:mountains], @images[:kitten], @images[:drake] ]
|
18
|
+
|
19
|
+
# models = [:apparel,
|
20
|
+
# :celebrity,
|
21
|
+
# :color,
|
22
|
+
# :demographics,
|
23
|
+
# :face_detection,
|
24
|
+
# :face_embedding,
|
25
|
+
# :focus,
|
26
|
+
# :food,
|
27
|
+
# :general,
|
28
|
+
# :general_embedding,
|
29
|
+
# :logo,
|
30
|
+
# :moderation,
|
31
|
+
# :nsfw,
|
32
|
+
# :travel,
|
33
|
+
# :wedding ]
|
15
34
|
|
16
35
|
@client = Clarification::Client.new
|
17
|
-
|
36
|
+
# @client.set_models(models)
|
37
|
+
# @response = @client.predict(@target_url)
|
38
|
+
|
39
|
+
# @client.search.index_image
|
40
|
+
# @client.search.by_concepts
|
41
|
+
# @client.search.by_images
|
42
|
+
|
18
43
|
|
19
44
|
# (If you use this, don't forget to add pry to your Gemfile!)
|
20
45
|
require "pry"
|
data/clarification.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.email = ["nichol.alexander@gmail.com"]
|
11
11
|
|
12
12
|
spec.summary = %q{An unofficial API wrapper for the Clarifai Image and Video Recognition API.}
|
13
|
-
spec.description = %q{Alpha Version -
|
13
|
+
spec.description = %q{Alpha Version - Predict and Search using Clarifai.}
|
14
14
|
spec.homepage = "https://github.com/nicholalexander/clarification"
|
15
15
|
spec.license = "MIT"
|
16
16
|
|
data/lib/clarification.rb
CHANGED
@@ -1,9 +1,15 @@
|
|
1
1
|
require "clarification/client"
|
2
|
+
require "clarification/concept"
|
2
3
|
require "clarification/configuration"
|
3
4
|
require "clarification/end_points"
|
4
5
|
require "clarification/enrich"
|
6
|
+
require "clarification/hit"
|
5
7
|
require "clarification/objectifier"
|
8
|
+
require "clarification/response"
|
9
|
+
require "clarification/response/search_response"
|
6
10
|
require "clarification/requester"
|
11
|
+
require "clarification/requester/search_requester"
|
12
|
+
require "clarification/search"
|
7
13
|
require "clarification/version"
|
8
14
|
|
9
15
|
require 'net/http'
|
data/lib/clarification/client.rb
CHANGED
@@ -1,23 +1,28 @@
|
|
1
1
|
module Clarification
|
2
2
|
class Client
|
3
3
|
|
4
|
-
attr_reader :
|
4
|
+
attr_reader :active_public_models, :last_response, :search
|
5
5
|
|
6
6
|
def initialize
|
7
7
|
raise "No Configuration Found." if Clarification.configuration.nil?
|
8
|
-
@
|
8
|
+
@active_public_models = Clarification.configuration.default_public_models
|
9
9
|
@last_response = nil
|
10
|
+
@search = Search.new
|
10
11
|
end
|
11
12
|
|
12
13
|
def predict(url)
|
13
|
-
requester = Requester.new(@
|
14
|
+
requester = Requester.new(@active_public_models)
|
14
15
|
response = requester.get(url)
|
15
16
|
@last_response = Enrich.new(response).run
|
16
17
|
return @last_response
|
17
18
|
end
|
18
19
|
|
19
20
|
def set_models(model_array)
|
20
|
-
|
21
|
+
if model_array.class != Array
|
22
|
+
raise "Clarification expects an array of models."
|
23
|
+
end
|
24
|
+
|
25
|
+
@active_public_models = model_array
|
21
26
|
end
|
22
27
|
|
23
28
|
end
|
data/lib/clarification/enrich.rb
CHANGED
@@ -1,21 +1,67 @@
|
|
1
1
|
module Clarification
|
2
2
|
class Objectifier
|
3
3
|
|
4
|
-
attr_reader :response_json, :status, :concepts
|
4
|
+
attr_reader :response_json, :status, :concepts, :error
|
5
5
|
|
6
6
|
def initialize(response)
|
7
7
|
@response_json = JSON.parse(response)
|
8
8
|
@status = OpenStruct.new(@response_json["status"])
|
9
9
|
@concepts = []
|
10
|
-
|
10
|
+
@error = nil
|
11
|
+
|
11
12
|
build_concept_objects
|
13
|
+
|
12
14
|
end
|
13
15
|
|
14
16
|
def build_concept_objects
|
15
|
-
|
16
|
-
|
17
|
+
|
18
|
+
begin
|
19
|
+
concepts = @response_json.fetch("outputs").fetch(0).fetch("data", nil).fetch("concepts", nil)
|
20
|
+
rescue StandardError => e
|
21
|
+
@error = e
|
22
|
+
return
|
23
|
+
end
|
24
|
+
|
25
|
+
if concepts
|
26
|
+
concepts.each do |concept_hash|
|
27
|
+
|
28
|
+
name = concept_hash["name"]
|
29
|
+
value = concept_hash["value"]
|
30
|
+
|
31
|
+
concept = Concept.new(name, value)
|
32
|
+
|
33
|
+
@concepts << concept
|
34
|
+
end
|
35
|
+
else
|
36
|
+
data = @response_json.fetch("outputs").fetch(0).fetch("data", nil)
|
37
|
+
unless data.empty?
|
38
|
+
case @response_json['outputs'][0]['model']['name']
|
39
|
+
when "focus"
|
40
|
+
# concept.class = concept::focus
|
41
|
+
focus = OpenStruct.new(data["focus"])
|
42
|
+
regions = []
|
43
|
+
data["regions"].each do |region|
|
44
|
+
regions << OpenStruct.new(region)
|
45
|
+
end
|
46
|
+
focus_hash = {focus: focus, regions: regions}
|
47
|
+
@concepts << OpenStruct.new(focus_hash)
|
48
|
+
@concepts.first.name = "focus"
|
49
|
+
when "color"
|
50
|
+
# concept.class = concept::color
|
51
|
+
data["colors"].each do |color|
|
52
|
+
@concepts << OpenStruct.new(color)
|
53
|
+
end
|
54
|
+
when "general_embedding"
|
55
|
+
# concept.class = concept::embedding
|
56
|
+
@concepts << OpenStruct.new(data["embeddings"][0])
|
57
|
+
@concepts.first.name = "embedding"
|
58
|
+
end
|
59
|
+
end
|
17
60
|
end
|
61
|
+
|
18
62
|
end
|
19
63
|
|
20
64
|
end
|
21
65
|
end
|
66
|
+
|
67
|
+
|
@@ -13,6 +13,8 @@ module Clarification
|
|
13
13
|
return response
|
14
14
|
end
|
15
15
|
|
16
|
+
private
|
17
|
+
|
16
18
|
def get_with_model(target_url, model)
|
17
19
|
uri = uri_builder(model)
|
18
20
|
body = body_builder(target_url)
|
@@ -44,14 +46,14 @@ module Clarification
|
|
44
46
|
|
45
47
|
def uri_builder(model)
|
46
48
|
model_key = Clarification::PUBLIC_MODELS[model]
|
47
|
-
url = "#{Clarification::BASE_URL}
|
49
|
+
url = "#{Clarification::BASE_URL}models/#{model_key}/outputs"
|
48
50
|
uri = URI.parse(url)
|
49
51
|
end
|
50
52
|
|
51
53
|
def request_builder(uri, body)
|
52
54
|
request = Net::HTTP::Post.new(uri)
|
53
55
|
request.content_type = "application/json"
|
54
|
-
request["Authorization"] = "Key
|
56
|
+
request["Authorization"] = "Key #{Clarification.configuration.api_key}"
|
55
57
|
request.body = JSON.dump(body)
|
56
58
|
|
57
59
|
return request
|
@@ -61,10 +63,20 @@ module Clarification
|
|
61
63
|
request_options = {
|
62
64
|
use_ssl: uri.scheme == "https",
|
63
65
|
}
|
64
|
-
|
65
66
|
return request_options
|
66
67
|
end
|
67
68
|
|
69
|
+
def get_response(uri, body)
|
70
|
+
request = request_builder(uri, body)
|
71
|
+
options = options_builder(uri)
|
72
|
+
|
73
|
+
response = Net::HTTP.start(uri.hostname, uri.port, options) do |http|
|
74
|
+
http.request(request)
|
75
|
+
end
|
76
|
+
|
77
|
+
return response
|
78
|
+
|
79
|
+
end
|
68
80
|
|
69
81
|
|
70
82
|
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module Clarification
|
2
|
+
class SearchRequester < Clarification::Requester
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
end
|
6
|
+
|
7
|
+
def index(target_urls)
|
8
|
+
uri = uri_builder("inputs")
|
9
|
+
body = body_builder(target_urls)
|
10
|
+
response = get_response(uri, body)
|
11
|
+
return response
|
12
|
+
end
|
13
|
+
|
14
|
+
def get_results_for_concept(concept)
|
15
|
+
uri = uri_builder("searches")
|
16
|
+
body = concept_body_builder(concept)
|
17
|
+
response = get_response(uri, body)
|
18
|
+
return response
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def body_builder(target_urls)
|
24
|
+
# build individual inputs
|
25
|
+
inputs = []
|
26
|
+
target_urls.each do |url|
|
27
|
+
inputs << {
|
28
|
+
data: {
|
29
|
+
image: {
|
30
|
+
url: url
|
31
|
+
}
|
32
|
+
}
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
# wrap for api
|
37
|
+
{
|
38
|
+
inputs: inputs
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
def concept_body_builder(concept)
|
43
|
+
{
|
44
|
+
query: {
|
45
|
+
ands: [
|
46
|
+
{
|
47
|
+
output: {
|
48
|
+
data: {
|
49
|
+
concepts: [
|
50
|
+
{
|
51
|
+
name: "#{concept}"
|
52
|
+
}
|
53
|
+
]
|
54
|
+
}
|
55
|
+
}
|
56
|
+
}
|
57
|
+
]
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
def uri_builder(path)
|
65
|
+
url = "#{Clarification::BASE_URL}#{path}"
|
66
|
+
URI.parse(url)
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Clarification
|
2
|
+
|
3
|
+
class SearchResponse < Response
|
4
|
+
|
5
|
+
attr_reader :hits, :raw_response, :concept
|
6
|
+
|
7
|
+
def initialize(raw_response, concept)
|
8
|
+
@hits = []
|
9
|
+
@concept = concept
|
10
|
+
@raw_response = JSON.parse(raw_response)
|
11
|
+
|
12
|
+
parse_raw_response
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
def parse_raw_response
|
17
|
+
@raw_response['hits'].each do |hit|
|
18
|
+
score = hit["score"]
|
19
|
+
url = hit["input"]["data"]["image"]["url"]
|
20
|
+
created_at = hit["input"]["created_at"]
|
21
|
+
@hits << Hit.new(score, url, created_at)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Clarification
|
2
|
+
class Search
|
3
|
+
|
4
|
+
attr_reader :last_search
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@last_search = nil
|
8
|
+
end
|
9
|
+
|
10
|
+
def index_images(image_array)
|
11
|
+
search_requester = Clarification::SearchRequester.new
|
12
|
+
search_requester.index(image_array)
|
13
|
+
# need some useful response here
|
14
|
+
end
|
15
|
+
|
16
|
+
def by_images(_image_array)
|
17
|
+
raise "Not Implemented"
|
18
|
+
end
|
19
|
+
|
20
|
+
def by_concept(concept)
|
21
|
+
search_requester = Clarification::SearchRequester.new
|
22
|
+
raw_response = search_requester.get_results_for_concept(concept)
|
23
|
+
structured_response = Clarification::SearchResponse.new(raw_response.body, concept)
|
24
|
+
@last_search = structured_response
|
25
|
+
return structured_response
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: clarification
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nichol Alexander
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-09-
|
11
|
+
date: 2017-09-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|
@@ -136,8 +136,7 @@ dependencies:
|
|
136
136
|
- - ">="
|
137
137
|
- !ruby/object:Gem::Version
|
138
138
|
version: '0'
|
139
|
-
description: Alpha Version -
|
140
|
-
responses.
|
139
|
+
description: Alpha Version - Predict and Search using Clarifai.
|
141
140
|
email:
|
142
141
|
- nichol.alexander@gmail.com
|
143
142
|
executables: []
|
@@ -158,11 +157,17 @@ files:
|
|
158
157
|
- clarification.gemspec
|
159
158
|
- lib/clarification.rb
|
160
159
|
- lib/clarification/client.rb
|
160
|
+
- lib/clarification/concept.rb
|
161
161
|
- lib/clarification/configuration.rb
|
162
162
|
- lib/clarification/end_points.rb
|
163
163
|
- lib/clarification/enrich.rb
|
164
|
+
- lib/clarification/hit.rb
|
164
165
|
- lib/clarification/objectifier.rb
|
165
166
|
- lib/clarification/requester.rb
|
167
|
+
- lib/clarification/requester/search_requester.rb
|
168
|
+
- lib/clarification/response.rb
|
169
|
+
- lib/clarification/response/search_response.rb
|
170
|
+
- lib/clarification/search.rb
|
166
171
|
- lib/clarification/version.rb
|
167
172
|
homepage: https://github.com/nicholalexander/clarification
|
168
173
|
licenses:
|