Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
C
crowdsourcehinter
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
OpenEdx
crowdsourcehinter
Commits
c602fdbf
Commit
c602fdbf
authored
Dec 10, 2014
by
solashirai
Committed by
Piotr Mitros
Oct 12, 2015
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
changes to flow of hinting/feedback mostly in place
parent
e22d313f
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
36 additions
and
70 deletions
+36
-70
crowdsourcehinter/crowdsourcehinter.py
+21
-45
crowdsourcehinter/static/css/crowdsourcehinter.css
+1
-7
crowdsourcehinter/static/html/crowdsourcehinter.html
+3
-4
crowdsourcehinter/static/js/src/crowdsourcehinter.js
+11
-14
No files found.
crowdsourcehinter/crowdsourcehinter.py
View file @
c602fdbf
...
...
@@ -8,7 +8,7 @@ import pkg_resources
import
random
from
xblock.core
import
XBlock
from
xblock.fields
import
Scope
,
Dict
,
List
from
xblock.fields
import
Scope
,
Dict
,
List
,
Boolean
from
xblock.fragment
import
Fragment
log
=
logging
.
getLogger
(
__name__
)
...
...
@@ -26,13 +26,10 @@ class CrowdsourceHinter(XBlock):
# This is a list of incorrect answer submissions made by the student. this list is mostly used for
# feedback, to find which incorrect answer's hint a student voted on.
WrongAnswers
=
List
([],
scope
=
Scope
.
user_state
)
# This list will keep track of what student answers didn't have a hint to show them. This list is used for
# the feedback stage, where students will be prompted and strongly encouraged to provide a hint for such hintless answers.
NoHintsFor
=
List
([],
scope
=
Scope
.
user_state
)
# A dictionary of default hints. default hints will be shown to students when there are no matches with the
# student's incorrect answer within the hint_database dictionary (i.e. no students have made hints for the
# particular incorrect answer)
DefaultHints
=
Dict
(
default
=
{
'default_hint'
:
0
},
scope
=
Scope
.
content
)
DefaultHints
=
Dict
(
default
=
{},
scope
=
Scope
.
content
)
# List of which hints have been shown to the student
# this list is used to prevent the same hint from showing up to a student (if they submit the same incorrect answers
# multiple times)
...
...
@@ -44,12 +41,11 @@ class CrowdsourceHinter(XBlock):
# This is a dictionary of hints that have been flagged. the values represent the incorrect answer submission, and the
# keys are the hints the corresponding hints. hints with identical text for differing answers will all not show up for the
# student.
Flagged
=
Dict
(
default
=
{
"This is a hint that should be flagged"
:
"answer2"
},
scope
=
Scope
.
user_state_summary
)
Flagged
=
Dict
(
default
=
{},
scope
=
Scope
.
user_state_summary
)
# This string determines whether or not to show only the best (highest rated) hint to a student
# When set to 'True' only the best hint will be shown to the student.
# Details on operation when set to 'False' are to be finalized.
# TODO: make this into a boolean instead of a dict
show_best
=
Dict
(
default
=
{
'showbest'
:
'True'
},
scope
=
Scope
.
user_state_summary
)
show_best
=
Boolean
(
default
=
True
,
scope
=
Scope
.
user_state_summary
)
def
student_view
(
self
,
context
=
None
):
"""
...
...
@@ -132,9 +128,11 @@ class CrowdsourceHinter(XBlock):
eqplace
=
answer
.
index
(
"="
)
+
1
answer
=
answer
[
eqplace
:]
remaining_hints
=
str
(
self
.
find_hints
(
answer
))
print
(
answer
)
print
(
remaining_hints
)
if
remaining_hints
!=
str
(
0
):
best_hint
=
max
(
self
.
hint_database
[
str
(
answer
)]
.
iteritems
(),
key
=
operator
.
itemgetter
(
1
))[
0
]
if
self
.
show_best
[
'showbest'
]
==
'True'
:
if
self
.
show_best
:
# if set to show best, only the best hint will be shown. Different hitns will not be shown
# for multiple submissions/hint requests
if
best_hint
not
in
self
.
Flagged
.
keys
():
...
...
@@ -145,7 +143,6 @@ class CrowdsourceHinter(XBlock):
if
best_hint
not
in
self
.
Flagged
.
keys
():
self
.
Used
.
append
(
best_hint
)
return
{
'HintsToUse'
:
best_hint
,
"StudentAnswer"
:
answer
}
else
:
# choose another random hint for the answer.
temporary_hints_list
=
[]
for
hint_keys
in
self
.
hint_database
[
str
(
answer
)]:
...
...
@@ -153,26 +150,20 @@ class CrowdsourceHinter(XBlock):
if
hint_keys
not
in
self
.
Flagged
:
temporary_hints_list
.
append
(
str
(
hint_keys
))
not_used
=
random
.
choice
(
temporary_hints_list
)
else
:
if
best_hint
not
in
self
.
Used
:
# choose highest rated hint for the incorrect answer
if
best_hint
not
in
self
.
Flagged
.
keys
():
self
.
Used
.
append
(
best_hint
)
return
{
'HintsToUse'
:
best_hint
,
"StudentAnswer"
:
answer
}
self
.
Used
.
append
(
not_used
)
return
{
'HintsToUse'
:
not_used
,
"StudentAnswer"
:
answer
}
else
:
temporary_hints_list
=
[]
for
hint_keys
in
self
.
DefaultHints
:
if
hint_keys
not
in
self
.
Used
:
temporary_hints_list
.
append
(
str
(
hint_keys
))
if
len
(
temporary_hints_list
)
!=
0
:
not_used
=
random
.
choice
(
temporary_hints_list
)
self
.
Used
.
append
(
not_used
)
return
{
'HintsToUse'
:
not_used
,
"StudentAnswer"
:
answer
}
else
:
# if there are no more hints left in either the database or defaults
self
.
Used
.
append
(
str
(
"There are no hints for"
+
" "
+
answer
))
self
.
NoHintsFor
.
append
(
answer
)
return
{
'HintsToUse'
:
"Sorry, there are no more hints for this answer."
,
"StudentAnswer"
:
answer
}
self
.
Used
.
append
(
not_used
)
return
{
'HintsToUse'
:
not_used
,
"StudentAnswer"
:
answer
}
return
{
'HintsToUse'
:
"Sorry, there are no hints for this answer."
,
"StudentAnswer"
:
answer
}
def
find_hints
(
self
,
answer
):
"""
...
...
@@ -181,6 +172,8 @@ class CrowdsourceHinter(XBlock):
Args:
answer: This is equal to answer from get_hint, the answer the student submitted
Returns 0 if no hints to show exist
"""
isflagged
=
[]
isused
=
0
...
...
@@ -194,6 +187,7 @@ class CrowdsourceHinter(XBlock):
if
hint_keys
==
flagged_keys
:
isflagged
.
append
(
hint_keys
)
if
str
(
hint_keys
)
in
self
.
Used
:
if
self
.
show_best
is
False
:
isused
+=
1
if
(
len
(
self
.
hint_database
[
str
(
answer
)])
-
len
(
isflagged
)
-
isused
)
>
0
:
return
str
(
1
)
...
...
@@ -219,10 +213,10 @@ class CrowdsourceHinter(XBlock):
if
len
(
self
.
WrongAnswers
)
==
0
:
return
else
:
print
(
self
.
Used
)
for
index
in
range
(
0
,
len
(
self
.
Used
)):
# each index is a hint that was used, in order of usage
for
answer_keys
in
self
.
hint_database
:
if
str
(
self
.
Used
[
index
])
in
self
.
hint_database
[
str
(
answer_keys
)]:
if
str
(
self
.
Used
[
index
])
in
self
.
hint_database
[
self
.
WrongAnswers
[
index
]]:
# add new key (hint) to feedback_data with a value (incorrect answer)
feedback_data
[
str
(
self
.
Used
[
index
])]
=
str
(
self
.
WrongAnswers
[
index
])
else
:
...
...
@@ -334,27 +328,9 @@ class CrowdsourceHinter(XBlock):
else
:
temporary_dictionary
[
str
(
data_hint
)]
-=
1
self
.
hint_database
[
str
(
answer_data
)]
=
temporary_dictionary
print
(
self
.
hint_database
)
return
str
(
temporary_dictionary
[
str
(
data_hint
)])
def
remove_symbols
(
self
,
answer_data
):
"""
For removing colons and such from answers to prevent weird things from happening. Not sure if this is properly functional.
Args:
answer_data: This is equal to the data['answer'] in self.rate_hint
Returns:
answer_data: This is equal to the argument answer_data except that symbols have been
replaced by text (hopefully)
"""
answer_data
=
answer_data
.
replace
(
'ddeecciimmaallppooiinntt'
,
'.'
)
answer_data
=
answer_data
.
replace
(
'qquueessttiioonnmmaarrkk'
,
'?'
)
answer_data
=
answer_data
.
replace
(
'ccoolloonn'
,
':'
)
answer_data
=
answer_data
.
replace
(
'sseemmiiccoolloonn'
,
';'
)
answer_data
=
answer_data
.
replace
(
'eeqquuaallss'
,
'='
)
answer_data
=
answer_data
.
replace
(
'qquuoottaattiioonnmmaarrkkss'
,
'"'
)
return
answer_data
@XBlock.json_handler
def
moderate_hint
(
self
,
data
,
suffix
=
''
):
"""
...
...
@@ -422,7 +398,7 @@ class CrowdsourceHinter(XBlock):
return
[
(
"CrowdsourceHinter"
,
"""<vertical_demo>
<crowdsourcehinter/>
</vertical_demo>
"""
),
<crowdsourcehinter/>
</vertical_demo>
"""
),
]
crowdsourcehinter/static/css/crowdsourcehinter.css
View file @
c602fdbf
...
...
@@ -14,11 +14,7 @@
.csh_hint_value
{
display
:
flex
;
margin-left
:
10px
;
}
.csh_rating_data
{
width
:
10%
;
vertical-align
:
middle
;
flex-direction
:
column
;
}
.crowdsourcehinter_block
.csh_HintsToUse
{
...
...
@@ -37,8 +33,6 @@
}
.csh_hint_data
{
justify-content
:
center
;
width
:
90%
;
display
:
flex
;
flex-direction
:
column
;
}
...
...
crowdsourcehinter/static/html/crowdsourcehinter.html
View file @
c602fdbf
<script
type=
'x-tmpl/mustache'
id=
'show_hint_feedback'
>
<
div
class
=
'csh_hint_value'
value
=
"{{hintvalue}}"
>
<
div
class
=
'csh_hint_data'
>
<
div
class
=
"csh_hint"
>
{{
hint
}}
<
/div
>
<
/div
>
<
div
class
=
'csh_rating_data'
>
<
div
role
=
"button"
class
=
"csh_rate_hint"
data
-
rate
=
"upvote"
data
-
icon
=
"arrow-u"
aria
-
label
=
"upvote"
>
<
b
>
This
hint
was
helpful
<
/b
>
<
/div
>
//
<
div
class
=
"csh_rating"
>
{{
rating
}}
<
/div
>
<
div
role
=
"button"
class
=
"csh_rate_hint"
data
-
rate
=
"downvote"
aria
-
label
=
"downvote"
>
<
b
>
This
hint
was
not
helpful
<
/b
>
<
/div
>
<
/div
>
<
div
class
=
'csh_hint_data'
>
<
div
class
=
"csh_hint"
>
{{
hint
}}
<
/div
>
<
div
role
=
"button"
class
=
"csh_rate_hint"
data
-
rate
=
"flag"
data
-
icon
=
"flag"
aria
-
label
=
"flag"
>
<
b
>
Report
this
hint
<
/b
>
<
/div
>
...
...
crowdsourcehinter/static/js/src/crowdsourcehinter.js
View file @
c602fdbf
...
...
@@ -38,7 +38,7 @@ function CrowdsourceHinter(runtime, element){
}
else
{
$
(
'.csh_correct'
,
element
).
show
();
$
(
'.csh_correct'
,
element
).
text
(
"You're correct! Please help us improve our hints by voting on them, or submit your own hint!"
);
$
(
".csh_
HintsToUse"
,
element
).
text
(
" "
);
$
(
".csh_
hint_reveal"
,
element
).
hide
(
);
//send empty data for ajax call because not having a data field causes error
$
.
ajax
({
type
:
"POST"
,
...
...
@@ -58,7 +58,7 @@ function CrowdsourceHinter(runtime, element){
type
:
"POST"
,
url
:
runtime
.
handlerUrl
(
element
,
'get_feedback'
),
data
:
JSON
.
stringify
({
"isStaff"
:
"false"
}),
success
:
get
Student
Feedback
success
:
getFeedback
});
}
}
...
...
@@ -72,11 +72,11 @@ function CrowdsourceHinter(runtime, element){
$
(
'.csh_HintsToUse'
,
element
).
text
(
result
.
HintsToUse
);
}
function
showHintFeedback
(
hint
){
function
showHintFeedback
(
hint
,
student_answer
){
//Append answer-specific hints for each student answer during the feedback stage.
//This appended div includes upvote/downvote/flagging buttons, the hint, and the hint's rating
$
(
".csh_student_answer"
,
element
).
each
(
function
(){
if
(
$
(
this
).
find
(
"span"
).
text
()
==
result
.
student_answer
){
if
(
$
(
this
).
find
(
"span"
).
text
()
==
student_answer
){
var
html
=
""
;
$
(
function
(){
var
data
=
{
...
...
@@ -105,18 +105,14 @@ function CrowdsourceHinter(runtime, element){
function
setStudentAnswers
(
student_answers
){
//Append divs for each answer the student submitted before correctly answering the question.
//showHintFeedback appends new hints into these divs.
for
(
var
i
=
0
;
i
<
student_answers
.
length
;
i
++
){
var
html
=
""
;
$
(
function
(){
var
template
=
$
(
'#show_answer_feedback'
).
html
();
var
data
=
{
answer
:
student_answers
[
i
]
answer
:
student_answers
};
html
=
Mustache
.
render
(
template
,
data
);
});
$
(
".csh_feedback"
,
element
).
append
(
html
);
}
}
function
getFeedback
(
result
){
//Set up the student feedback stage. Each student answer and all answer-specific hints for that answer are shown
...
...
@@ -134,17 +130,18 @@ function CrowdsourceHinter(runtime, element){
$
(
".csh_student_answer"
,
element
).
each
(
function
(){
if
(
$
(
this
).
find
(
"span"
).
text
()
==
student_answer
){
var
html
=
""
;
$
(
function
(){
var
template
=
$
(
'#show_no_hints'
).
html
();
var
data
=
{};
html
=
Mustache
.
render
(
template
,
data
);
}
);
$
(
this
).
append
(
html
);
console
.
log
(
html
);
$
(
this
).
find
(
"span"
).
append
(
html
);
}
});
}
//flagged hints have their corresponding answer set to "Flagged"
showHintFeedback
(
hint
);
else
{
showHintFeedback
(
hint
,
student_answer
);
}
});
isShowingHintFeedback
=
true
;
}
...
...
@@ -188,7 +185,7 @@ function CrowdsourceHinter(runtime, element){
type
:
"POST"
,
url
:
runtime
.
handlerUrl
(
element
,
'get_ratings'
),
data
:
JSON
.
stringify
({
"student_answer"
:
answerdata
,
"hint"
:
newhint
}),
success
:
showHintFeedback
success
:
showHintFeedback
(
newhint
,
answerdata
)
});
}
});
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment