shared_workforce 0.2.14 → 0.3.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.
- data/README.markdown +18 -0
- data/lib/shared_workforce/configuration.rb +10 -6
- data/lib/shared_workforce/frameworks/rails.rb +4 -1
- data/lib/shared_workforce/response_collector.rb +50 -0
- data/lib/shared_workforce/task.rb +2 -0
- data/lib/shared_workforce/task_request/{http_with_poller.rb → http_without_callbacks.rb} +1 -1
- data/lib/shared_workforce/tasks/collect.rake +19 -0
- data/lib/shared_workforce/version.rb +1 -1
- data/lib/shared_workforce.rb +2 -2
- data/spec/task_request/{http_with_poller_spec.rb → http_without_callbacks_spec.rb} +2 -2
- metadata +17 -16
- data/lib/shared_workforce/response_poller.rb +0 -52
data/README.markdown
CHANGED
@@ -81,6 +81,14 @@ end
|
|
81
81
|
```
|
82
82
|
_**Note:** the task definition includes a `setup` method which is called automatically whenever the task is initialized. In the example, the task's `image_url` (the image shown to the worker) is set from the photo model's url attribute. Any of the task's attributes can be set this way._
|
83
83
|
|
84
|
+
Class level attributes are a handy way of defining data that doesn't change between each task.
|
85
|
+
Attributes set on the instance will always override attributes set at the class level.
|
86
|
+
|
87
|
+
In most cases, you'll want to explicitly set default task values at the class level
|
88
|
+
(like `title` and `instruction`). Setting `text`
|
89
|
+
and `image_url` values (i.e. the content in question) will usually be done in
|
90
|
+
the `setup` method.</p>
|
91
|
+
|
84
92
|
Once you have created a task definition, you can request real human responses for a model instance by calling its `create` method. This can be done in an `after_create` callback in one of your Active Record models. This will be covered in more detail in the next section.
|
85
93
|
|
86
94
|
### Step 4 - request tasks
|
@@ -102,6 +110,16 @@ _**Note:** In the example, the photo model instance (self) is used an argument t
|
|
102
110
|
|
103
111
|
When the response(s) from the human workers are collected, the method specified in the `on_success` attribute in your task definition will be called. Typically this will take about 15 minutes. You can check the [Shared Workforce web site](http://www.sharedworkforce.com) for an up to date status on the current response time.
|
104
112
|
|
113
|
+
### Step 5 - collect responses
|
114
|
+
|
115
|
+
A rake task is provided for collecting the responses *during development*.
|
116
|
+
|
117
|
+
```
|
118
|
+
$ rake sw:collect
|
119
|
+
```
|
120
|
+
|
121
|
+
There is no requirement to run the rake task in production. The webhook will be used to deliver the task responses.
|
122
|
+
|
105
123
|
### Unit testing
|
106
124
|
|
107
125
|
You can test your task definition by calling its methods directly.
|
@@ -31,7 +31,7 @@ module SharedWorkforce
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def logger
|
34
|
-
@logger ||=
|
34
|
+
@logger ||= default_logger
|
35
35
|
end
|
36
36
|
|
37
37
|
def valid?
|
@@ -43,7 +43,7 @@ module SharedWorkforce
|
|
43
43
|
def default_request_class
|
44
44
|
if defined?(Rails)
|
45
45
|
if Rails.env.development?
|
46
|
-
TaskRequest::
|
46
|
+
TaskRequest::HttpWithoutCallbacks
|
47
47
|
elsif Rails.env.test?
|
48
48
|
TaskRequest::BlackHole
|
49
49
|
else
|
@@ -60,10 +60,14 @@ module SharedWorkforce
|
|
60
60
|
end
|
61
61
|
|
62
62
|
def default_logger
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
63
|
+
if !rails_logger || (defined?(Rails) && Rails.env.development?)
|
64
|
+
require 'logger'
|
65
|
+
l = ::Logger.new($stdout)
|
66
|
+
l.level = ::Logger::INFO
|
67
|
+
l
|
68
|
+
else
|
69
|
+
rails_logger
|
70
|
+
end
|
67
71
|
end
|
68
72
|
end
|
69
73
|
end
|
@@ -7,12 +7,15 @@ if defined?(ActionController::Metal)
|
|
7
7
|
if SharedWorkforce.configuration.valid?
|
8
8
|
# Stop log buffering when using Foreman in development
|
9
9
|
$stdout.sync = true
|
10
|
-
SharedWorkforce::ResponsePoller.start
|
11
10
|
else
|
12
11
|
puts 'Shared Workforce: API key not configured.'
|
13
12
|
end
|
14
13
|
end
|
15
14
|
end
|
16
15
|
end
|
16
|
+
|
17
|
+
rake_tasks do
|
18
|
+
load "shared_workforce/tasks/collect.rake" if Rails.env.development?
|
19
|
+
end
|
17
20
|
end
|
18
21
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module SharedWorkforce
|
2
|
+
class ResponseCollector
|
3
|
+
|
4
|
+
attr_accessor :interval
|
5
|
+
|
6
|
+
def self.start(interval=nil)
|
7
|
+
new.start(interval)
|
8
|
+
end
|
9
|
+
|
10
|
+
def start(interval)
|
11
|
+
@interval = interval
|
12
|
+
process_tasks completed_tasks
|
13
|
+
sleep interval if interval
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def process_tasks(tasks)
|
19
|
+
if tasks.any?
|
20
|
+
tasks.each do |task|
|
21
|
+
if task['state'] == "completed"
|
22
|
+
SharedWorkforce.logger.info "=> #{task['title']} (#{task['id']}) complete. Loading responses."
|
23
|
+
responses = collect_responses(task['id'])
|
24
|
+
|
25
|
+
SharedWorkforce::TaskResult.new(responses).process!
|
26
|
+
SharedWorkforce.logger.info "=> Done."
|
27
|
+
end
|
28
|
+
end
|
29
|
+
elsif !interval
|
30
|
+
SharedWorkforce.logger.info "=> No responses to collect."
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def completed_tasks
|
35
|
+
JSON.parse(RestClient.get("#{SharedWorkforce.configuration.http_end_point}/tasks/unreturned", {
|
36
|
+
'X-API-Key'=>SharedWorkforce.configuration.api_key,
|
37
|
+
:content_type => :json,
|
38
|
+
:accept => :json
|
39
|
+
}))
|
40
|
+
end
|
41
|
+
|
42
|
+
def collect_responses(id)
|
43
|
+
JSON.parse(RestClient.get("#{SharedWorkforce.configuration.http_end_point}/tasks/#{id}/responses/collect", {
|
44
|
+
'X-API-Key'=>SharedWorkforce.configuration.api_key,
|
45
|
+
:content_type => :json,
|
46
|
+
:accept => :json
|
47
|
+
}))
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -90,6 +90,7 @@ module SharedWorkforce
|
|
90
90
|
end
|
91
91
|
|
92
92
|
def process_result(result)
|
93
|
+
SharedWorkforce.logger.info("Shared Workforce: processing responses for #{title}")
|
93
94
|
initialize_attributes(result.callback_params)
|
94
95
|
success!(result)
|
95
96
|
complete!(result)
|
@@ -112,6 +113,7 @@ module SharedWorkforce
|
|
112
113
|
end
|
113
114
|
|
114
115
|
def request(options = {})
|
116
|
+
SharedWorkforce.logger.info("Shared Workforce: creating task #{title}")
|
115
117
|
task_request = remote_request(self, options)
|
116
118
|
task_request.create
|
117
119
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'rest_client'
|
2
2
|
module SharedWorkforce
|
3
|
-
class TaskRequest::
|
3
|
+
class TaskRequest::HttpWithoutCallbacks < TaskRequest::Http
|
4
4
|
# Disable callbacks during development
|
5
5
|
def request_params
|
6
6
|
[{:task=>@task.to_hash.merge(@params).merge(:callback_url=>callback_url, :callback_enabled=>false), :api_key=>api_key}.to_json, {:content_type => :json, :accept => :json}]
|
@@ -0,0 +1,19 @@
|
|
1
|
+
desc "Collects completed responses"
|
2
|
+
namespace :shared_workforce do
|
3
|
+
task :collect => :environment do
|
4
|
+
$stdout.sync = true
|
5
|
+
puts "=> Please note: expect a delay of about 30 seconds after a task is completed before seeing a response."
|
6
|
+
puts "=> This gives the worker a chance to change their answer."
|
7
|
+
puts "=> Connecting to Shared Workforce..."
|
8
|
+
SharedWorkforce::ResponseCollector.start
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
namespace :sw do
|
13
|
+
desc "Alias of shared_workforce:collect"
|
14
|
+
task :collect => "shared_workforce:collect"
|
15
|
+
end
|
16
|
+
|
17
|
+
namespace :sharedworkforce do
|
18
|
+
task :collect => "shared_workforce:collect"
|
19
|
+
end
|
data/lib/shared_workforce.rb
CHANGED
@@ -6,11 +6,11 @@ require 'shared_workforce/task'
|
|
6
6
|
require 'shared_workforce/task_request/task_request'
|
7
7
|
require 'shared_workforce/task_request/black_hole'
|
8
8
|
require 'shared_workforce/task_request/http'
|
9
|
-
require 'shared_workforce/task_request/
|
9
|
+
require 'shared_workforce/task_request/http_without_callbacks'
|
10
10
|
require 'shared_workforce/task_result'
|
11
11
|
require 'shared_workforce/task_response'
|
12
12
|
require 'shared_workforce/end_point'
|
13
|
-
require 'shared_workforce/
|
13
|
+
require 'shared_workforce/response_collector'
|
14
14
|
require 'shared_workforce/frameworks/rails' if defined?(Rails)
|
15
15
|
require 'active_support/inflector'
|
16
16
|
require 'active_support/core_ext/hash/indifferent_access'
|
@@ -1,10 +1,10 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
2
|
|
3
|
-
describe "TaskRequest::
|
3
|
+
describe "TaskRequest::HttpWithoutCallbacks" do
|
4
4
|
describe "#create" do
|
5
5
|
it "should disable callbacks" do
|
6
6
|
task = ApprovePhotoTask.new
|
7
|
-
task_request = SharedWorkforce::TaskRequest::
|
7
|
+
task_request = SharedWorkforce::TaskRequest::HttpWithoutCallbacks.new(task,
|
8
8
|
:image_url=>"http://www.google.com/logo.png",
|
9
9
|
:image_crop_ratio=>1.7,
|
10
10
|
:callback_params=>{:resource_id=>'1234'}
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shared_workforce
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-09-
|
12
|
+
date: 2012-09-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rest-client
|
16
|
-
requirement: &
|
16
|
+
requirement: &70263277593000 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70263277593000
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: json
|
27
|
-
requirement: &
|
27
|
+
requirement: &70263277592580 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70263277592580
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: activesupport
|
38
|
-
requirement: &
|
38
|
+
requirement: &70263277608420 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70263277608420
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: rspec
|
49
|
-
requirement: &
|
49
|
+
requirement: &70263277607380 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: 1.2.9
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70263277607380
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: webmock
|
60
|
-
requirement: &
|
60
|
+
requirement: &70263277606740 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,7 +65,7 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70263277606740
|
69
69
|
description: Shared Workforce is a service and simple API for human intelligence tasks
|
70
70
|
email:
|
71
71
|
- sam@samoliver.com
|
@@ -84,14 +84,15 @@ files:
|
|
84
84
|
- lib/shared_workforce/end_point.rb
|
85
85
|
- lib/shared_workforce/exceptions.rb
|
86
86
|
- lib/shared_workforce/frameworks/rails.rb
|
87
|
-
- lib/shared_workforce/
|
87
|
+
- lib/shared_workforce/response_collector.rb
|
88
88
|
- lib/shared_workforce/task.rb
|
89
89
|
- lib/shared_workforce/task_request/black_hole.rb
|
90
90
|
- lib/shared_workforce/task_request/http.rb
|
91
|
-
- lib/shared_workforce/task_request/
|
91
|
+
- lib/shared_workforce/task_request/http_without_callbacks.rb
|
92
92
|
- lib/shared_workforce/task_request/task_request.rb
|
93
93
|
- lib/shared_workforce/task_response.rb
|
94
94
|
- lib/shared_workforce/task_result.rb
|
95
|
+
- lib/shared_workforce/tasks/collect.rake
|
95
96
|
- lib/shared_workforce/version.rb
|
96
97
|
- shared_workforce.gemspec
|
97
98
|
- spec/.rspec
|
@@ -103,7 +104,7 @@ files:
|
|
103
104
|
- spec/support/configuration_helper.rb
|
104
105
|
- spec/task_request/black_hole_spec.rb
|
105
106
|
- spec/task_request/http_spec.rb
|
106
|
-
- spec/task_request/
|
107
|
+
- spec/task_request/http_without_callbacks_spec.rb
|
107
108
|
- spec/task_response_spec.rb
|
108
109
|
- spec/task_result_spec.rb
|
109
110
|
- spec/task_spec.rb
|
@@ -141,7 +142,7 @@ test_files:
|
|
141
142
|
- spec/support/configuration_helper.rb
|
142
143
|
- spec/task_request/black_hole_spec.rb
|
143
144
|
- spec/task_request/http_spec.rb
|
144
|
-
- spec/task_request/
|
145
|
+
- spec/task_request/http_without_callbacks_spec.rb
|
145
146
|
- spec/task_response_spec.rb
|
146
147
|
- spec/task_result_spec.rb
|
147
148
|
- spec/task_spec.rb
|
@@ -1,52 +0,0 @@
|
|
1
|
-
module SharedWorkforce
|
2
|
-
class ResponsePoller
|
3
|
-
# The response poller is intended for use during local development only. It
|
4
|
-
# facilitates real world task responses without needing an open socket for the
|
5
|
-
# web hooks.
|
6
|
-
|
7
|
-
def self.start(interval=60)
|
8
|
-
new.start(interval)
|
9
|
-
end
|
10
|
-
|
11
|
-
def start(interval)
|
12
|
-
Thread.abort_on_exception = true
|
13
|
-
Thread.new do
|
14
|
-
SharedWorkforce.logger.info "SharedWorkforce: Checking every #{interval} seconds for new responses."
|
15
|
-
|
16
|
-
while true
|
17
|
-
SharedWorkforce.logger.info "SharedWorkforce: Checking for new task responses."
|
18
|
-
process_tasks completed_tasks
|
19
|
-
sleep interval
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
private
|
25
|
-
|
26
|
-
def process_tasks(tasks)
|
27
|
-
tasks.each do |task|
|
28
|
-
if task['state'] == "completed"
|
29
|
-
SharedWorkforce.logger.info "SharedWorkforce: Task complete. Getting responses."
|
30
|
-
responses = collect_responses(task['id'])
|
31
|
-
SharedWorkforce::TaskResult.new(responses).process!
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def completed_tasks
|
37
|
-
JSON.parse(RestClient.get("#{SharedWorkforce.configuration.http_end_point}/tasks/unreturned", {
|
38
|
-
'X-API-Key'=>SharedWorkforce.configuration.api_key,
|
39
|
-
:content_type => :json,
|
40
|
-
:accept => :json
|
41
|
-
}))
|
42
|
-
end
|
43
|
-
|
44
|
-
def collect_responses(id)
|
45
|
-
JSON.parse(RestClient.get("#{SharedWorkforce.configuration.http_end_point}/tasks/#{id}/responses/collect", {
|
46
|
-
'X-API-Key'=>SharedWorkforce.configuration.api_key,
|
47
|
-
:content_type => :json,
|
48
|
-
:accept => :json
|
49
|
-
}))
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|