Lower HIT reward
[oweals/karmaworld.git] / karmaworld / apps / quizzes / tasks.py
1 #!/usr/bin/env python
2 # -*- coding:utf8 -*-
3 # Copyright (C) 2013  FinalsClub Foundation
4 from boto.mturk.qualification import PercentAssignmentsApprovedRequirement, Qualifications
5 from boto.mturk.question import Overview, FormattedContent, QuestionContent, Question, FreeTextAnswer, QuestionForm, \
6     AnswerSpecification
7 from celery import task
8 from celery.utils.log import get_task_logger
9 from boto.mturk.connection import MTurkConnection
10 from django.contrib.sites.models import Site
11 from django.core.exceptions import ObjectDoesNotExist
12 from karmaworld.apps.notes.models import Note
13 from karmaworld.apps.quizzes.models import Keyword
14
15 logger = get_task_logger(__name__)
16
17 HIT_TITLE = 'Choose keywords and descriptions from course notes'
18 HIT_DESCRIPTION = "Read students' course notes on Karmanotes.org and " \
19                   "identify 10 keywords along with descriptions of them"
20 HIT_OVERVIEW_TEMPLATE = \
21         '<p>Go to the page at KarmaNotes.org by clicking the link provided below. ' \
22         '<strong>Identify 10 key words (or short phrases) that are the most important to the document</strong> ' \
23         'on the page. This requires reading and understanding the document. Write these words in the boxes below. ' \
24         'Then, write definitions or descriptions of these keywords as they are provided in the page. ' \
25         'If the page does not provide a definition or description, leave the box blank. ' \
26         'For example, keywords might be &quot;John Locke,&quot; &quot;the Protestant reformation,&quot; ' \
27         'or &quot;existentialism.&quot; Their respective definitions or descriptions might be &quot;life, ' \
28         'liberty, and property,&quot; &quot;schism in Christianity started by Martin Luther,&quot; and ' \
29         '&quot;existence precedes essence.&quot;</p>' \
30         '<p>Notes link: <strong><a href="http://{domain}{link}">' \
31         'http://{domain}{link}</a></strong></p>'
32 HIT_KEYWORDS = 'writing, summary, keywords'
33 HIT_DURATION = 60 * 60 * 24 * 7
34 HIT_REWARD = 0.92
35 HIT_PERCENT_APPROVED_REQUIREMENT = PercentAssignmentsApprovedRequirement(comparator='GreaterThan', integer_value=95)
36 HIT_QUALIFICATION = Qualifications(requirements=[HIT_PERCENT_APPROVED_REQUIREMENT])
37
38 KEYWORD_FIELDS = [
39     ('keyword01', 'Keyword 1'),
40     ('keyword02', 'Keyword 2'),
41     ('keyword03', 'Keyword 3'),
42     ('keyword04', 'Keyword 4'),
43     ('keyword05', 'Keyword 5'),
44     ('keyword06', 'Keyword 6'),
45     ('keyword07', 'Keyword 7'),
46     ('keyword08', 'Keyword 8'),
47     ('keyword09', 'Keyword 9'),
48     ('keyword10', 'Keyword 10'),
49 ]
50
51 DEFINITION_FIELDS = [
52     ('definition01', 'Definition 1'),
53     ('definition02', 'Definition 2'),
54     ('definition03', 'Definition 3'),
55     ('definition04', 'Definition 4'),
56     ('definition05', 'Definition 5'),
57     ('definition06', 'Definition 6'),
58     ('definition07', 'Definition 7'),
59     ('definition08', 'Definition 8'),
60     ('definition09', 'Definition 9'),
61     ('definition10', 'Definition 10'),
62 ]
63
64 @task()
65 def submit_extract_keywords_hit(note):
66     """Create a Mechanical Turk HIT that asks a worker to
67     choose keywords and definitions from the given note."""
68
69     try:
70         from karmaworld.secret.mturk import AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, MTURK_HOST
71     except ImportError:
72         logger.warn('Could not find Mechanical Turk secrets, not running submit_extract_keywords_hit')
73         return
74
75     connection = MTurkConnection(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY,
76                                  host=MTURK_HOST)
77
78     overview = Overview()
79     overview.append(FormattedContent(HIT_OVERVIEW_TEMPLATE.format(domain=Site.objects.get_current(),
80                                                                   link=note.get_absolute_url())))
81
82     keyword_fta = FreeTextAnswer()
83     keyword_fta.num_lines = 1
84
85     definition_fta = FreeTextAnswer()
86     definition_fta.num_lines = 3
87
88     question_form = QuestionForm()
89     question_form.append(overview)
90
91     for i in range(min(len(KEYWORD_FIELDS), len(DEFINITION_FIELDS))):
92         keyword_content = QuestionContent()
93         keyword_content.append_field('Title', KEYWORD_FIELDS[i][1])
94         keyword_question = Question(identifier=KEYWORD_FIELDS[i][0],
95                                     content=keyword_content,
96                                     answer_spec=AnswerSpecification(keyword_fta),
97                                     is_required=True)
98         question_form.append(keyword_question)
99
100         definition_content = QuestionContent()
101         definition_content.append_field('Title', DEFINITION_FIELDS[i][1])
102         definition_question = Question(identifier=DEFINITION_FIELDS[i][0],
103                                        content=definition_content,
104                                        answer_spec=AnswerSpecification(definition_fta),
105                                        is_required=False)
106         question_form.append(definition_question)
107
108     connection.create_hit(questions=question_form, max_assignments=1,
109                           title=HIT_TITLE, description=HIT_DESCRIPTION,
110                           keywords=HIT_KEYWORDS, duration=HIT_DURATION,
111                           reward=HIT_REWARD, qualifications=HIT_QUALIFICATION,
112                           annotation=str(note.id))
113
114
115 @task(name='get_extract_keywords_results')
116 def get_extract_keywords_results():
117
118     try:
119         from karmaworld.secret.mturk import AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, MTURK_HOST
120     except ImportError:
121         logger.warn('Could not find Mechanical Turk secrets, not running get_extract_keywords_results')
122         return
123
124     connection = MTurkConnection(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY,
125                                  host=MTURK_HOST)
126
127     reviewable_hits = connection.get_reviewable_hits(page_size=100)
128     for hit in reviewable_hits:
129         try:
130             note_id = connection.get_hit(hit.HITId)[0].RequesterAnnotation
131         except AttributeError:
132             logger.error('HIT {0} does not have a RequesterAnnotation, '
133                          'so we cannot determine which note it references'.format(hit.HITId))
134             return
135
136         try:
137             note = Note.objects.get(id=note_id)
138         except ObjectDoesNotExist:
139             logger.error('Could not find note {0} which was referenced by HIT {1}'.format(note_id, hit.HITId))
140             return
141
142         answers = {}
143         assignments = [a for a in connection.get_assignments(hit.HITId) if a.AssignmentStatus == 'Submitted']
144         for assignment in assignments:
145             for question_form_answer in assignment.answers[0]:
146                 answers[question_form_answer.qid] = question_form_answer.fields[0]
147
148         for i in range(min(len(KEYWORD_FIELDS), len(DEFINITION_FIELDS))):
149             keyword_qid = KEYWORD_FIELDS[i][0]
150             definition_qid = DEFINITION_FIELDS[i][0]
151             try:
152                 keyword = answers[keyword_qid]
153                 definition = answers[definition_qid]
154                 Keyword.objects.create(word=keyword, definition=definition, note=note, unreviewed=True)
155             except KeyError:
156                 pass
157
158         for assignment in assignments:
159             connection.approve_assignment(assignment.AssignmentId)
160
161         connection.dispose_hit(hit.HITId)