cloudfactory 0.4.4 → 0.4.5
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +7 -0
- data/lib/cf.rb +4 -1
- data/lib/cf/badge.rb +59 -0
- data/lib/cf/cli.rb +6 -0
- data/lib/cf/cli/line.rb +185 -132
- data/lib/cf/cli/line_yaml_validator.rb +7 -30
- data/lib/cf/cli/production.rb +63 -9
- data/lib/cf/gold_standard.rb +74 -0
- data/lib/cf/help.txt +67 -0
- data/lib/cf/human_worker.rb +45 -49
- data/lib/cf/line.rb +51 -1
- data/lib/cf/run.rb +10 -10
- data/lib/cf/station.rb +111 -29
- data/lib/cf/test_run.rb +66 -0
- data/lib/cf/version.rb +1 -1
- data/spec/account_spec.rb +1 -1
- data/spec/badges/station_1.html +135 -0
- data/spec/badges_spec.rb +288 -0
- data/spec/gold_standard_spec.rb +179 -0
- data/spec/gold_standards.csv +2 -0
- data/spec/google_translate_robot_spec.rb +1 -1
- data/spec/human_worker_spec.rb +1 -65
- data/spec/line_spec.rb +6 -39
- data/spec/robot_worker_spec.rb +1 -1
- data/spec/run_spec.rb +9 -7
- data/spec/stat_badge_spec.rb +45 -0
- data/spec/test_run_spec.rb +105 -0
- metadata +264 -218
- data/spec/badge_spec.rb +0 -88
data/lib/cf/line.rb
CHANGED
@@ -38,6 +38,7 @@ module CF
|
|
38
38
|
def initialize(title, department_name, options={})
|
39
39
|
@input_formats =[]
|
40
40
|
@stations =[]
|
41
|
+
@gold_standards = []
|
41
42
|
@title = title
|
42
43
|
@department_name = department_name
|
43
44
|
@public = options[:public].nil? ? true : options[:public]
|
@@ -222,10 +223,59 @@ module CF
|
|
222
223
|
@output_formats
|
223
224
|
end
|
224
225
|
end
|
225
|
-
|
226
|
+
|
226
227
|
def output_formats=(output_format) # :nodoc:
|
227
228
|
@output_formats = output_format
|
228
229
|
end
|
230
|
+
|
231
|
+
|
232
|
+
#specify the goldstandards for the line
|
233
|
+
# ===Usage Example:
|
234
|
+
# CF::GoldStandard.new({ :line => line,:name => "easy", :input => [{'image_url' =>"http://onwired.com/images/portfolio/linda-stanley-business-card.jpg"}],:expected_output => [{"first_name" => {"value" => "John"}, "last_name" => {"value" => "Lennon"}, "company" => {"value" => "Sprout"}}]})
|
235
|
+
def gold_standards gold_standard = nil
|
236
|
+
if gold_standard
|
237
|
+
line = self
|
238
|
+
gold_standard_options = gold_standard.settings
|
239
|
+
if !gold_standard_options.nil?
|
240
|
+
# check whether the gold standard is from a file or not(check for bulk assignment of goldstandards)
|
241
|
+
if gold_standard_options[:file]
|
242
|
+
puts gold_standard_options[:file]
|
243
|
+
if File.exist?(gold_standard_options[:file].to_s)
|
244
|
+
file_upload = File.new(gold_standard_options[:file], 'rb')
|
245
|
+
resp = self.class.post("/lines/#{CF.account_name}/#{line.title.downcase}/gold_standards.json", {:file => file_upload})
|
246
|
+
gold_standard = CF::GoldStandard.new()
|
247
|
+
resp.each do |gs|
|
248
|
+
gold_standard.settings.merge!(gs.to_hash)
|
249
|
+
end
|
250
|
+
end
|
251
|
+
else
|
252
|
+
request =
|
253
|
+
{
|
254
|
+
:body =>
|
255
|
+
{
|
256
|
+
:api_key => CF.api_key,
|
257
|
+
:gold_standard => gold_standard_options
|
258
|
+
}
|
259
|
+
}
|
260
|
+
resp = HTTParty.post("#{CF.api_url}#{CF.api_version}/lines/#{CF.account_name}/#{line.title.downcase}/gold_standards.json",request)
|
261
|
+
gold_standard = CF::GoldStandard.new()
|
262
|
+
resp.parsed_response.first.delete("id")
|
263
|
+
gold_standard.settings.merge!(resp.parsed_response.first.symbolize_keys)
|
264
|
+
self.errors = resp.parsed_response['error']['message'] if resp.code != 200
|
265
|
+
end
|
266
|
+
@gold_standards << gold_standard
|
267
|
+
end
|
268
|
+
else
|
269
|
+
@gold_standards
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
|
274
|
+
def gold_standards=(gold_standard) # :nodoc:
|
275
|
+
@gold_standards << gold_standard
|
276
|
+
end
|
277
|
+
|
278
|
+
|
229
279
|
# ==Returns the content of a line by making an Api call
|
230
280
|
# ===Usage Example:
|
231
281
|
# CF::Line.info(line)
|
data/lib/cf/run.rb
CHANGED
@@ -168,38 +168,38 @@ module CF
|
|
168
168
|
return resp
|
169
169
|
end
|
170
170
|
end
|
171
|
-
|
171
|
+
|
172
172
|
# ==Returns progress of the production run
|
173
173
|
# ===Usage Example:
|
174
174
|
# progress = CF::Run.progress("run_title")
|
175
175
|
def self.progress(run_title)
|
176
176
|
get("/runs/#{CF.account_name}/#{run_title}/progress.json")
|
177
177
|
end
|
178
|
-
|
178
|
+
|
179
179
|
def progress # :nodoc:
|
180
180
|
self.class.get("/runs/#{CF.account_name}/#{self.title}/progress.json")
|
181
181
|
end
|
182
|
-
|
182
|
+
|
183
183
|
# ==Returns progress details of the production run
|
184
184
|
# ===Usage Example:
|
185
185
|
# progress = CF::Run.progress_details("run_title")
|
186
186
|
def self.progress_details(run_title)
|
187
|
-
resp = get("/runs/#{CF.account_name}/#{run_title}/
|
188
|
-
return resp['
|
187
|
+
resp = get("/runs/#{CF.account_name}/#{run_title}/progress.json")
|
188
|
+
return resp['progress']
|
189
189
|
end
|
190
|
-
|
190
|
+
|
191
191
|
def progress_details # :nodoc:
|
192
|
-
resp = self.class.get("/runs/#{CF.account_name}/#{self.title}/
|
193
|
-
return resp['
|
192
|
+
resp = self.class.get("/runs/#{CF.account_name}/#{self.title}/progress.json")
|
193
|
+
return resp['progress']
|
194
194
|
end
|
195
|
-
|
195
|
+
|
196
196
|
# ==Returns all runs of a line
|
197
197
|
# ===Usage Example:
|
198
198
|
# progress = CF::Run.all({:line_title => "line_title", :page => 1)
|
199
199
|
def self.all(options={})
|
200
200
|
page = options[:page].presence
|
201
201
|
line_title = options[:line_title].presence
|
202
|
-
|
202
|
+
|
203
203
|
if line_title.nil?
|
204
204
|
if page.nil?
|
205
205
|
resp = get("/runs/#{CF.account_name}.json")
|
data/lib/cf/station.rb
CHANGED
@@ -11,22 +11,22 @@ module CF
|
|
11
11
|
|
12
12
|
# Index number of station
|
13
13
|
attr_accessor :index
|
14
|
-
|
14
|
+
|
15
15
|
# Line attribute of the station with which station is associated
|
16
16
|
attr_accessor :line
|
17
|
-
|
17
|
+
|
18
18
|
# Manual input format settings for the station
|
19
19
|
attr_accessor :station_input_formats
|
20
|
-
|
20
|
+
|
21
21
|
# Jury worker settings for the Tournament Station
|
22
22
|
attr_accessor :jury_worker
|
23
|
-
|
23
|
+
|
24
24
|
# Auto Judge settings for the Tournament Station
|
25
25
|
attr_accessor :auto_judge
|
26
|
-
|
26
|
+
|
27
27
|
# Contains Error Message if any
|
28
28
|
attr_accessor :errors
|
29
|
-
|
29
|
+
|
30
30
|
# batch_size attribute, required for specifing size of batch
|
31
31
|
attr_accessor :batch_size
|
32
32
|
|
@@ -37,6 +37,7 @@ module CF
|
|
37
37
|
# line.stations station
|
38
38
|
def initialize(options={})
|
39
39
|
@input_formats =[]
|
40
|
+
@badges = []
|
40
41
|
@line_title = options[:line].nil? ? nil : options[:line].title
|
41
42
|
@type = options[:type].nil? ? nil : options[:type].camelize
|
42
43
|
@jury_worker = options[:jury_worker]
|
@@ -44,29 +45,30 @@ module CF
|
|
44
45
|
@station_input_formats = options[:input_formats]
|
45
46
|
@line_instance = options[:line]
|
46
47
|
@batch_size = options[:batch_size]
|
48
|
+
@gold_standards = []
|
47
49
|
@acceptance_ratio = options[:acceptance_ratio]
|
48
50
|
if @batch_size.nil?
|
49
|
-
request_general =
|
51
|
+
request_general =
|
50
52
|
{
|
51
|
-
:body =>
|
53
|
+
:body =>
|
52
54
|
{
|
53
55
|
:api_key => CF.api_key,
|
54
56
|
:station => {:type => @type, :input_formats => @station_input_formats}
|
55
57
|
}
|
56
58
|
}
|
57
59
|
if @acceptance_ratio.nil?
|
58
|
-
request_tournament =
|
60
|
+
request_tournament =
|
59
61
|
{
|
60
|
-
:body =>
|
62
|
+
:body =>
|
61
63
|
{
|
62
64
|
:api_key => CF.api_key,
|
63
65
|
:station => {:type => @type, :jury_worker => @jury_worker, :auto_judge => @auto_judge, :input_formats => @station_input_formats}
|
64
66
|
}
|
65
67
|
}
|
66
68
|
else
|
67
|
-
request_tournament =
|
69
|
+
request_tournament =
|
68
70
|
{
|
69
|
-
:body =>
|
71
|
+
:body =>
|
70
72
|
{
|
71
73
|
:api_key => CF.api_key,
|
72
74
|
:station => {:type => @type, :jury_worker => @jury_worker, :auto_judge => @auto_judge, :input_formats => @station_input_formats, :acceptance_ratio => @acceptance_ratio}
|
@@ -74,27 +76,27 @@ module CF
|
|
74
76
|
}
|
75
77
|
end
|
76
78
|
else
|
77
|
-
request_general =
|
79
|
+
request_general =
|
78
80
|
{
|
79
|
-
:body =>
|
81
|
+
:body =>
|
80
82
|
{
|
81
83
|
:api_key => CF.api_key,
|
82
84
|
:station => {:type => @type, :input_formats => @station_input_formats, :batch_size => @batch_size}
|
83
85
|
}
|
84
86
|
}
|
85
87
|
if @acceptance_ratio.nil?
|
86
|
-
request_tournament =
|
88
|
+
request_tournament =
|
87
89
|
{
|
88
|
-
:body =>
|
90
|
+
:body =>
|
89
91
|
{
|
90
92
|
:api_key => CF.api_key,
|
91
93
|
:station => {:type => @type, :jury_worker => @jury_worker, :auto_judge => @auto_judge, :input_formats => @station_input_formats, :batch_size => @batch_size}
|
92
94
|
}
|
93
95
|
}
|
94
96
|
else
|
95
|
-
request_tournament =
|
97
|
+
request_tournament =
|
96
98
|
{
|
97
|
-
:body =>
|
99
|
+
:body =>
|
98
100
|
{
|
99
101
|
:api_key => CF.api_key,
|
100
102
|
:station => {:type => @type, :jury_worker => @jury_worker, :auto_judge => @auto_judge, :input_formats => @station_input_formats, :batch_size => @batch_size, :acceptance_ratio => @acceptance_ratio}
|
@@ -172,25 +174,23 @@ module CF
|
|
172
174
|
else
|
173
175
|
number = worker_instance.number
|
174
176
|
reward = worker_instance.reward
|
175
|
-
badge = worker_instance.badge
|
176
177
|
stat_badge = worker_instance.stat_badge
|
177
|
-
if
|
178
|
-
request =
|
178
|
+
if stat_badge.nil?
|
179
|
+
request =
|
179
180
|
{
|
180
|
-
:body =>
|
181
|
+
:body =>
|
181
182
|
{
|
182
183
|
:api_key => CF.api_key,
|
183
184
|
:worker => {:number => number, :reward => reward, :type => "HumanWorker"}
|
184
185
|
}
|
185
186
|
}
|
186
187
|
else
|
187
|
-
request =
|
188
|
+
request =
|
188
189
|
{
|
189
|
-
:body =>
|
190
|
+
:body =>
|
190
191
|
{
|
191
192
|
:api_key => CF.api_key,
|
192
193
|
:worker => {:number => number, :reward => reward, :type => "HumanWorker"},
|
193
|
-
:skill_badge => badge,
|
194
194
|
:stat_badge => stat_badge
|
195
195
|
}
|
196
196
|
}
|
@@ -200,8 +200,7 @@ module CF
|
|
200
200
|
worker.id = resp.parsed_response['id']
|
201
201
|
worker.number = resp.parsed_response['number']
|
202
202
|
worker.reward = resp.parsed_response['reward']
|
203
|
-
worker.stat_badge = resp.parsed_response['stat_badge']
|
204
|
-
worker.skill_badges << resp.parsed_response['skill_badges']
|
203
|
+
worker.stat_badge = resp.parsed_response['stat_badge']
|
205
204
|
if resp.code != 200
|
206
205
|
worker.errors = resp.parsed_response['error']['message']
|
207
206
|
end
|
@@ -264,7 +263,7 @@ module CF
|
|
264
263
|
@html = @form.raw_html
|
265
264
|
@resp = CF::CustomTaskForm.post("/lines/#{CF.account_name}/#{self.line_title.downcase}/stations/#{self.index}/form.json", :form => {:title => @title, :instruction => @instruction, :_type => "CustomTaskForm", :raw_html => @html})
|
266
265
|
else
|
267
|
-
@resp = CF::TaskForm.post("/lines/#{CF.account_name}/#{self.line_title.downcase}/stations/#{self.index}/form.json", :form => {:title => @title, :instruction => @instruction, :_type => type})
|
266
|
+
@resp = CF::TaskForm.post("/lines/#{CF.account_name}/#{self.line_title.downcase}/stations/#{self.index}/form.json", :form => {:title => @title, :instruction => @instruction, :_type => type})
|
268
267
|
end
|
269
268
|
@resp.to_hash.each_pair do |k,v|
|
270
269
|
form.send("#{k}=",v) if form.respond_to?(k)
|
@@ -319,7 +318,7 @@ module CF
|
|
319
318
|
self.errors = resp.error.message if resp.code != 200
|
320
319
|
return resp
|
321
320
|
end
|
322
|
-
|
321
|
+
|
323
322
|
def to_s # :nodoc:
|
324
323
|
if self.type == "TournamentStation"
|
325
324
|
"{:type => #{self.type}, :index => #{self.index}, :line_title => #{self.line_title}, :station_input_formats => #{self.station_input_formats}, :jury_worker => #{self.jury_worker}, auto_judge => #{self.auto_judge}, :errors => #{self.errors}}"
|
@@ -327,5 +326,88 @@ module CF
|
|
327
326
|
"{:type => #{self.type}, :index => #{self.index}, :line_title => #{self.line_title}, :station_input_formats => #{self.station_input_formats}, :errors => #{self.errors}}"
|
328
327
|
end
|
329
328
|
end
|
329
|
+
|
330
|
+
#specify the goldstandards for the station
|
331
|
+
# ===Usage Example:
|
332
|
+
# CF::GoldStandard.new({ :station => station,:name => "easy",:input => [{'image_url' =>"http://onwired.com/images/portfolio/linda-stanley-business-card.jpg"}],:expected_output => [{"first_name" => {"value" => "John"}, "last_name" => {"value" => "Lennon"}, "company" => {"value" => "Sprout"}}]})
|
333
|
+
def gold_standards gold_standard = nil
|
334
|
+
if gold_standard
|
335
|
+
station = self
|
336
|
+
gold_standard_options = gold_standard.settings
|
337
|
+
if !gold_standard_options.nil?
|
338
|
+
if gold_standard_options[:file]
|
339
|
+
if File.exist?(gold_standard_options[:file].to_s)
|
340
|
+
file_upload = File.new(gold_standard_options[:file], 'rb')
|
341
|
+
resp = self.class.post("/lines/#{CF.account_name}/#{line.title.downcase}/gold_standards.json", {:file => file_upload})
|
342
|
+
gold_standard = CF::GoldStandard.new()
|
343
|
+
resp.each do |gs|
|
344
|
+
gold_standard.settings.merge!(gs.to_hash)
|
345
|
+
end
|
346
|
+
end
|
347
|
+
else
|
348
|
+
request =
|
349
|
+
{
|
350
|
+
:body =>
|
351
|
+
{
|
352
|
+
:api_key => CF.api_key,
|
353
|
+
:gold_standard => gold_standard_options
|
354
|
+
}
|
355
|
+
}
|
356
|
+
resp = HTTParty.post("#{CF.api_url}#{CF.api_version}/lines/#{CF.account_name}/#{line.title.downcase}/stations/#{station.index.to_i}/gold_standards.json",request)
|
357
|
+
gold_standard = CF::GoldStandard.new()
|
358
|
+
resp.parsed_response.first.delete("id")
|
359
|
+
gold_standard.settings.merge!(resp.parsed_response.first.symbolize_keys)
|
360
|
+
self.errors = resp.parsed_response['error']['message'] if resp.code != 200
|
361
|
+
end
|
362
|
+
@gold_standards << gold_standard
|
363
|
+
end
|
364
|
+
else
|
365
|
+
@gold_standards
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
def gold_standards=(gold_standard) # :nodoc:
|
370
|
+
@gold_standards << gold_standard
|
371
|
+
end
|
372
|
+
|
373
|
+
#specify the badges for the station
|
374
|
+
# ===Usage Example:
|
375
|
+
# CF::Badge.new({:line => line, :station => s,:name => "Tomb Digitizer", :description => "This badge qualifies you to work on tomb digitization tasks.",:max_badges => 100,:gold_standards => ["#{@gold_standard.settings[:name]}"],:test_attributes =>{:type => "default",:retries => 10,:pass_percentage => 100,:check_manually => true}})
|
376
|
+
def badges badge = nil
|
377
|
+
line_title = line["title"] || line.title
|
378
|
+
if badge
|
379
|
+
if badge.settings[:test_attributes][:form_attributes].present?
|
380
|
+
form = badge.settings[:test_attributes][:form_attributes]
|
381
|
+
if( form[:type] == "CustomTaskForm" && form[:file])
|
382
|
+
raw_html = ""
|
383
|
+
File.open("#{form[:file]}").each_line do |line|
|
384
|
+
raw_html += line
|
385
|
+
end
|
386
|
+
badge.settings[:test_attributes][:form_attributes].merge!({:raw_html => raw_html,:_type =>"CustomTaskForm"})
|
387
|
+
end
|
388
|
+
badge.settings[:test_attributes][:form_attributes].merge!({:_type =>"TaskForm"}) if form[:type] == "TaskForm"
|
389
|
+
end
|
390
|
+
request =
|
391
|
+
{
|
392
|
+
:body =>
|
393
|
+
{
|
394
|
+
:api_key => CF.api_key,
|
395
|
+
:badge => badge.settings
|
396
|
+
}
|
397
|
+
}
|
398
|
+
resp = HTTParty.post("#{CF.api_url}#{CF.api_version}/lines/#{CF.account_name}/#{line_title.downcase}/stations/#{self.index}/badges.json",request)
|
399
|
+
badge = CF::Badge.new()
|
400
|
+
badge.settings.merge!(resp.to_hash)
|
401
|
+
self.errors = resp.parsed_response['error']['message'] if resp.code != 200
|
402
|
+
@badges << badge
|
403
|
+
else
|
404
|
+
@badges
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
def badges=(badge)
|
409
|
+
@badges << badge
|
410
|
+
end
|
411
|
+
|
330
412
|
end
|
331
413
|
end
|
data/lib/cf/test_run.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
module CF
|
2
|
+
class TestRun
|
3
|
+
require 'httparty'
|
4
|
+
include Client
|
5
|
+
|
6
|
+
# Title of the "run" object
|
7
|
+
attr_accessor :title
|
8
|
+
|
9
|
+
# Input to be passed for Production Run
|
10
|
+
attr_accessor :gold_standard_inputs
|
11
|
+
|
12
|
+
# Line attribute with which run is associated
|
13
|
+
attr_accessor :line
|
14
|
+
|
15
|
+
# Contains Error Message if any
|
16
|
+
attr_accessor :errors
|
17
|
+
|
18
|
+
# ==Initializes a new Run
|
19
|
+
# ===Usage Example:
|
20
|
+
#
|
21
|
+
# run = CF::Run.new("line_title", "run name", file_path)
|
22
|
+
#
|
23
|
+
# ==OR
|
24
|
+
# You can pass line object instead of passing line title:
|
25
|
+
# run = CF::Run.new(line_object, "run name", file_path)
|
26
|
+
def initialize(line, title, gold_standards_number)
|
27
|
+
@gold_standards_number = gold_standards_number # a number that denotes how many goldstandard form line should be included to create units
|
28
|
+
if line.class == CF::Line || line.class == Hashie::Mash
|
29
|
+
@line = line
|
30
|
+
@line_title = line.title
|
31
|
+
elsif line.class == String
|
32
|
+
if line.split("/").count == 2
|
33
|
+
@account = line.split("/").first
|
34
|
+
@line_title = line.split("/").last
|
35
|
+
elsif line.split("/").count == 1
|
36
|
+
@line_title = line
|
37
|
+
end
|
38
|
+
end
|
39
|
+
@title = title
|
40
|
+
if gold_standards_number
|
41
|
+
options =
|
42
|
+
{
|
43
|
+
:body =>
|
44
|
+
{
|
45
|
+
:api_key => CF.api_key,
|
46
|
+
:data =>{:run => { :title => @title ,:test =>"true"}, :gold_standard_inputs => @gold_standards_number}
|
47
|
+
}
|
48
|
+
}
|
49
|
+
if line.class == String && line.split("/").count == 2
|
50
|
+
run = HTTParty.post("#{CF.api_url}#{CF.api_version}/lines/#{@account}/#{@line_title.downcase}/runs.json",options)
|
51
|
+
else
|
52
|
+
run = HTTParty.post("#{CF.api_url}#{CF.api_version}/lines/#{CF.account_name}/#{@line_title.downcase}/runs.json",options)
|
53
|
+
end
|
54
|
+
if run.code != 200
|
55
|
+
self.errors = run.parsed_response['error']['message']
|
56
|
+
end
|
57
|
+
else
|
58
|
+
self.errors = "Number of GoldStandards to be used is not provided"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.create(line, title, input_number)
|
63
|
+
TestRun.new(line, title, input_number)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
data/lib/cf/version.rb
CHANGED