From 775dd8eb5a7e4ef72e414a250667a8a28c0f877a Mon Sep 17 00:00:00 2001 From: Miguel Barão Date: Mon, 17 Dec 2018 14:27:09 +0000 Subject: [PATCH] - reorganized how the state machine of question answering to be in two steps (post and get). --- BUGS.md | 3 ++- demo/math/questions.yaml | 82 +++++++++++++++++++++++++++++++++++++++++----------------------------------------- knowledge.py | 20 +++++++------------- questions.py | 1 + serve.py | 113 ++++++++++++++++++++++++++++++++++++++++++++++++----------------------------------------------------------------- static/js/topic.js | 71 ++++++++++++++++++++++++++++++++++++++++++----------------------------- templates/comments-right.html | 9 +++++++++ 7 files changed, 150 insertions(+), 149 deletions(-) create mode 100644 templates/comments-right.html diff --git a/BUGS.md b/BUGS.md index bbe467b..5ad9115 100644 --- a/BUGS.md +++ b/BUGS.md @@ -1,7 +1,7 @@ # BUGS -- errar no ultimo topico nao mostra solucao? +- falha no file handler de vez em quando, nao sei porquê... - nos topicos learn.yaml, qd falha acrescenta no fim. nao faz sentido. - ocorreu uma vez o sqlalchemy dar mesg erro a indicar que as threads sao diferents quando se faz o get da primeira pergunta do topico. Muitas vezes nao mostar erro, mas a pagina da erro ou fica em branco... @@ -32,6 +32,7 @@ # FIXED +- errar no ultimo topico nao mostra solucao? - quando a pergunta devolve comments, este é apresentado, mas fica persistente nas tentativas seguintes. devia ser limpo apos a segunda submissao. - na definicao dos topicos, indicar: "file: questions.yaml" (default questions.yaml) diff --git a/demo/math/questions.yaml b/demo/math/questions.yaml index 88bd0f9..2c5b553 100644 --- a/demo/math/questions.yaml +++ b/demo/math/questions.yaml @@ -15,48 +15,48 @@ correct: [1,1,0,0,0] choose: 3 -# - ref: numbers -# type: checkbox -# title: Números pares e primos -# text: Indique as afirmações verdadeiras. -# options: -# - ['3 é primo', '4 é primo'] -# - ['2 é par', '3 é par'] -# - ['1 é ímpar', '2 é ímpar'] -# correct: [1,1,1] +- ref: numbers + type: checkbox + title: Números pares e primos + text: Indique as afirmações verdadeiras. + options: + - ['3 é primo', '4 é primo'] + - ['2 é par', '3 é par'] + - ['1 é ímpar', '2 é ímpar'] + correct: [1,1,1] -# - -# ref: prime_numbers -# type: radio -# title: Números primos -# text: Qual dos seguintes números é primo? -# options: -# - 13 -# - 12 -# - 14 -# - 1, a **unidade** +- + ref: prime_numbers + type: radio + title: Números primos + text: Qual dos seguintes números é primo? + options: + - 13 + - 12 + - 14 + - 1, a **unidade** -# # --------------------------------------------------------------------------- -# - -# ref: math-expressions -# type: checkbox -# title: Expressões matemáticas -# text: Quais das seguintes expressões são verdadeiras? -# options: -# - $1 > 0$ -# - $\sqrt{3} > \sqrt{2}$ -# - $e^{i\pi} + 1 = 0$ -# - $\frac{\partial f(x,y)}{\partial z} = 1$ -# - $-1 > 1$ -# # how many points for each checkmark (normalized afterwards): -# correct: [1, 1, 1, -1, -1] +# --------------------------------------------------------------------------- +- + ref: math-expressions + type: checkbox + title: Expressões matemáticas + text: Quais das seguintes expressões são verdadeiras? + options: + - $1 > 0$ + - $\sqrt{3} > \sqrt{2}$ + - $e^{i\pi} + 1 = 0$ + - $\frac{\partial f(x,y)}{\partial z} = 1$ + - $-1 > 1$ + # how many points for each checkmark (normalized afterwards): + correct: [1, 1, 1, -1, -1] -# # --------------------------------------------------------------------------- -# - -# ref: overflow -# type: generator -# script: generate-overflow.py -# # opcional -# arg: "11,120" -# # the script should print a question dict in yaml format. +# --------------------------------------------------------------------------- +- + ref: overflow + type: generator + script: generate-overflow.py + # opcional + arg: "11,120" + # the script should print a question dict in yaml format. diff --git a/knowledge.py b/knowledge.py index df60e57..d93cefa 100644 --- a/knowledge.py +++ b/knowledge.py @@ -135,28 +135,22 @@ class StudentKnowledge(object): if grade > 0.999: self.correct_answers += 1 - if self.next_question() is None: - action = 'finished_topic' - else: - action = 'new_question' + self.next_question() + action = 'right' else: self.wrong_answers += 1 self.current_question['tries'] -= 1 logger.debug(f'Wrong answers = {self.wrong_answers}; Tries = {self.current_question["tries"]}') - if self.current_question['tries'] <= 0: + if self.current_question['tries'] > 0: + action = 'try_again' + else: + action = 'wrong' if self.current_question['append_wrong']: logger.debug("Appending new instance of this question to the end") self.questions.append(self.factory[q['ref']].generate()) - - if self.next_question() is None: - action = 'finished_topic' - else: - action = 'wrong' # FIXME show comments - - else: - action = 'try_again' + self.next_question() # returns corrected question (not new one) which might include comments return q, action diff --git a/questions.py b/questions.py index 101eed8..ad2c80b 100644 --- a/questions.py +++ b/questions.py @@ -39,6 +39,7 @@ class Question(dict): 'title': '', 'answer': None, 'comments': '', + 'solution': '', 'files': {}, }) diff --git a/serve.py b/serve.py index a6280d7..22fb1fd 100755 --- a/serve.py +++ b/serve.py @@ -170,6 +170,9 @@ class TopicHandler(BaseHandler): # Serves files from the /public subdir of the topics. # Based on https://bhch.github.io/posts/2017/12/serving-large-files-with-tornado-safely-without-blocking/ # ---------------------------------------------------------------------------- + +# FIXME error in many situations... images are not shown... + class FileHandler(BaseHandler): SUPPORTED_METHODS = ['GET'] @@ -221,18 +224,29 @@ class QuestionHandler(BaseHandler): logging.debug('QuestionHandler.get()') user = self.current_user q = self.learn.get_current_question(user) - question_html = self.render_string(self.templates[q['type']], - question=q, md=md_to_html) - - response = { - 'method': 'new_question', - 'params': { - 'type': q['type'], - 'question': tornado.escape.to_unicode(question_html), - 'progress': self.learn.get_student_progress(user), - 'tries': q['tries'], - }, - } + + if q is not None: + question_html = self.render_string(self.templates[q['type']], + question=q, md=md_to_html) + response = { + 'method': 'new_question', + 'params': { + 'type': q['type'], + 'question': tornado.escape.to_unicode(question_html), + 'progress': self.learn.get_student_progress(user), + 'tries': q['tries'], + }, + } + + else: + finished_topic_html = self.render_string('finished_topic.html') + response = { + 'method': 'finished_topic', + 'params': { + 'question': tornado.escape.to_unicode(finished_topic_html) + } + } + self.write(response) # --- post answer, returns what to do next: shake, new_question, finished @@ -251,26 +265,30 @@ class QuestionHandler(BaseHandler): elif qtype != 'checkbox': # radio, text, textarea, ... answer = answer[0] - # check answer in another thread (nonblocking) - # and get corrected question + # check answer (nonblocking) and get corrected question q, action = await self.learn.check_answer(user, answer) - print(action) + response = {'method': action, 'params': {}} + + if action == 'right': # get next question in the topic + comments_html = self.render_string('comments-right.html', + comments=q['comments'], md=md_to_html) + + response['params'] = { + 'progress': self.learn.get_student_progress(user), + 'comments': tornado.escape.to_unicode(comments_html), + 'tries': q['tries'], + } - if action == 'try_again': + elif action == 'try_again': comments_html = self.render_string('comments.html', comments=q['comments'], md=md_to_html) - response = { - 'method': 'try_again', - 'params': { + response['params'] = { 'progress': self.learn.get_student_progress(user), 'comments': tornado.escape.to_unicode(comments_html), # FIXME 'tries': q['tries'], } - } - print(response) - self.write(response) elif action == 'wrong': # no more tries comments_html = self.render_string('comments.html', @@ -278,52 +296,17 @@ class QuestionHandler(BaseHandler): solution_html = self.render_string('solution.html', solution=q['solution'], md=md_to_html) - # template = self.templates[question['type']] - # question_html = self.render_string(template, question=question, md=md_to_html) - response = { - 'method': 'wrong', # FIXME js - 'params': { - # 'question': tornado.escape.to_unicode(question_html), - 'progress': self.learn.get_student_progress(user), - 'comments': tornado.escape.to_unicode(comments_html), # FIXME - 'solution': tornado.escape.to_unicode(solution_html), # FIXME - 'tries': q['tries'], - } - } - print(response) - self.write(response) - - elif action == 'new_question': # get next question in the topic - self.get() - # question = self.learn.get_current_question(user) - - # template = self.templates[question['type']] - # question_html = self.render_string(template, - # question=question, md=md_to_html) - # response = { - # 'method': 'new_question', - # 'params': { - # 'type': question['type'], - # 'question': tornado.escape.to_unicode(question_html), - # 'progress': self.learn.get_student_progress(user), - # 'tries': question['tries'], - # } - # } - # print(response) - # self.write(response) - - elif action == 'finished_topic': # right answer, finished topic - finished_topic_html = self.render_string('finished_topic.html') - response = { - 'method': 'finished_topic', - 'params': { - 'question': tornado.escape.to_unicode(finished_topic_html) - } + response['params'] = { + 'progress': self.learn.get_student_progress(user), + 'comments': tornado.escape.to_unicode(comments_html), + 'solution': tornado.escape.to_unicode(solution_html), + 'tries': q['tries'], } - self.write(response) else: - logger.error(f'Unknown action {action}') + logger.error(f'Unknown action: {action}') + + self.write(response) # ---------------------------------------------------------------------------- diff --git a/static/js/topic.js b/static/js/topic.js index f50fe57..126e802 100644 --- a/static/js/topic.js +++ b/static/js/topic.js @@ -7,6 +7,38 @@ $.fn.extend({ } }); +// Get current question +function getQuestion() { + $.ajax({ + type: "GET", + url: "/question", + dataType: "json", // expected from server + success: updateQuestion, + error: function() {alert("O servidor não responde.");} + }); +} + + +// updates question according to the response given by the server +function updateQuestion(response) { + var method = response["method"]; + var params = response["params"]; + + switch (method) { + case "new_question": + console.log(params["type"]); + new_question(params["type"], params["question"], params["tries"], params["progress"]); + break; + case "finished_topic": + $('#submit').hide(); + $("#content").html(response["params"]["question"]); + $('#topic_progress').css('width', '100%').attr('aria-valuenow', 100); + $("#content").animateCSS('tada'); + setTimeout(function(){ window.location.replace('/'); }, 2000); + break; + } +} + function new_question(type, question, tries, progress) { console.log("new_question " + type); @@ -39,19 +71,21 @@ function new_question(type, question, tries, progress) { } - -// updates question according to the response given by the server -function updateQuestion(response){ +function getFeedback(response) { console.log('updateQuestion '+response["method"]); var method = response["method"]; var params = response["params"]; - switch (method) { - case "new_question": - console.log(params["type"]); - new_question(params["type"], params["question"], params["tries"], params["progress"]); + case "right": + console.log(params['comments']); + $('#comments').html(params['comments']); + + // MathJax.Hub.Queue(["Typeset", MathJax.Hub, "#comments"]); + $("#submit").html("Continuar"); + $("#submit").off(); + $("#submit").click(getQuestion); break; case "try_again": @@ -75,30 +109,9 @@ function updateQuestion(response){ $("#submit").off(); $("#submit").click(getQuestion); break; - - case "finished_topic": - $('#submit').hide(); //css("visibility", "hidden"); - $("#content").html(response["params"]["question"]); - $('#topic_progress').css('width', '100%').attr('aria-valuenow', 100); - $("#content").animateCSS('tada'); - setTimeout(function(){ window.location.replace('/'); }, 2000); - break; } } -// Get current question -function getQuestion() { - console.log("getQuestion"); - - $.ajax({ - type: "GET", - url: "/question", - dataType: "json", // expected from server - success: updateQuestion, - error: function() {alert("O servidor não responde.");} - }); -} - // Send answer and receive a response. // The response can be a new_question or a shake if the answer is wrong, which // is then passed to updateQuestion() @@ -113,7 +126,7 @@ function postAnswer() { url: "/question", data: $("#question_form").serialize(), // {'a':10,'b':20}, dataType: "json", // expected from server - success: updateQuestion, + success: getFeedback, error: function() {alert("O servidor não responde.");} }); } diff --git a/templates/comments-right.html b/templates/comments-right.html new file mode 100644 index 0000000..b96c61a --- /dev/null +++ b/templates/comments-right.html @@ -0,0 +1,9 @@ +{% autoescape %} + +
+ Certo! + {% if comments %} +
+ {{ md(comments) }} + {% end %} +
-- libgit2 0.21.2