shared_workforce 0.2.14 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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 ||= (rails_logger || default_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::HttpWithPoller
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
- require 'logger'
64
- l = ::Logger.new($stdout)
65
- l.level = ::Logger::INFO
66
- l
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::HttpWithPoller < TaskRequest::Http
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
@@ -1,4 +1,4 @@
1
1
  module SharedWorkforce
2
- VERSION = "0.2.14"
2
+ VERSION = "0.3.0"
3
3
 
4
4
  end
@@ -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/http_with_poller'
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/response_poller'
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::HttpWithPoller" do
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::HttpWithPoller.new(task,
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.2.14
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-20 00:00:00.000000000 Z
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: &70318914187300 !ruby/object:Gem::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: *70318914187300
24
+ version_requirements: *70263277593000
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: json
27
- requirement: &70318914186880 !ruby/object:Gem::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: *70318914186880
35
+ version_requirements: *70263277592580
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: activesupport
38
- requirement: &70318914186460 !ruby/object:Gem::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: *70318914186460
46
+ version_requirements: *70263277608420
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rspec
49
- requirement: &70318914185960 !ruby/object:Gem::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: *70318914185960
57
+ version_requirements: *70263277607380
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: webmock
60
- requirement: &70318914185540 !ruby/object:Gem::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: *70318914185540
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/response_poller.rb
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/http_with_poller.rb
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/http_with_poller_spec.rb
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/http_with_poller_spec.rb
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