Пример #1
0
def create_question(language, *, odict):
    """Create a question document and save it to database."""

    question = Question(description="word flashcard",
                        skill="Vocabulary",
                        language=language.lower(),
                        word=odict["Word"],
                        part_of_speech=odict["Part_of_Speech"],
                        source_id=odict["Source_Id"])

    # css.DictReader escapes newline characters, so split with: '\\n '
    question.all_answers = odict["All_Answers"].split('\\n ')

    if odict["Child_Appropriate"].lower() == "no":
        question.child_appropriate = False

    question.audio = odict["Audio"].split(", ")

    question.images = []

    # adding info for the first image
    fileroot, ext = splitext(odict["Photo1"])
    ext = ext.lstrip(".")
    question.images.append([fileroot, ext, float(odict["Photo1_ar"])])

    # if there are more images, add info for them
    for i in [1, 2, 3]:
        if odict[f"Photo{i+1}"]:
            fileroot, ext = splitext(odict[f"Photo{i+1}"])
            ext = ext.lstrip(".")
            question.images.append(
                [fileroot, ext, float(odict[f"Photo{i+1}_ar"])])

    question.save()
Пример #2
0
def _read_question_from_json(language, side):
    """Read and return questions from json files.

    Generates a list of question ids and then for the first qusestion returns it
    as a Question object.

    Arguments:
    language: str -- language of the question
    side: "front" or "back"

    Return:
    Tuple: (a list of question ids, question as Question object)
    """

    os.chdir("C:/Users/Lukasz/Python/ErroresBuenos/lalang/questions/default")

    with open(f"stream_default_{language.lower()}_{side}.json", "r",
              encoding="utf8") as f:

        question_list = json.load(f)
        question_ids_list = []

        # store the question ids in a list
        for q in question_list:
            question_ids_list.append(q["id"])

        # for the first question, convert the dictionary into Question object
        question = Question()
        for k, v in question_list[0].items():
            setattr(question, k, v)

        return question_ids_list, question
Пример #3
0
def update_questions(db_name, language, filename):
    """Update questions from a csv file to a MongoDB database."""

    update_counter = 0
    added_counter = 0

    mongoengine.connect(db_name, host="localhost", port=27017)

    with open(filename, encoding="utf8") as csv_file:
        csv_reader = csv.DictReader(csv_file)
        for row in csv_reader:
            questions = Question.objects(language=language,
                                         source_id=row["Source_Id"])

            if questions.count() == 0:
                create_question(language, odict=row)
                added_counter += 1

            for question in questions:
                question.word = row["Word"]
                question.part_of_speech = row["Part_of_Speech"]
                question.hint = row["Hint"]
                question.source_id = row["Source_Id"]
                question.audio = row["Audio"].split(", ")

                if row["Child_Appropriate"].lower() == "no":
                    question.child_appropriate = False
                else:
                    question.child_appropriate = True

                # css.DictReader escapes newline characters, so split with:
                # '\\n '
                question.all_answers = row["All_Answers"].split('\\n ')

                question.part_of_speech = row["Part_of_Speech"]

                # preparing info for the first image
                fileroot, ext = splitext(row["Photo1"])
                ext = ext.lstrip(".")

                # updating the image array
                question.images = []
                question.images.append([fileroot, ext, float(row["Photo1_ar"])])

                # if there are more images, update them
                for i in [1, 2, 3]:
                    if row[f"Photo{i+1}"]:
                        fileroot, ext = splitext(row[f"Photo{i+1}"])
                        ext = ext.lstrip(".")
                        question.images.append([fileroot, ext,
                                                float(row[f"Photo{i+1}_ar"])])

                question.save()
                update_counter += 1

        print(f"Total records updated: {update_counter} for {language}")
        print(f"Total new records added: {added_counter} for {language}")
Пример #4
0
def get_queue_question(language, student_id):
    """Read and return first question stored in student's question queue in db.

    Read question queue in Student document, and use the id to
    retrieve a question from Question collection in db.

    Randomly pick between the "front" and "back" question queues.

    Return the question as a Question object, or None if
    no questions in queue.

    Argument:

    language: str
    student_id = str -- argument for ObjectId() in MongoDB

    Return:
    Tuple: (Question object or None, question side or None)
    """
    mongoengine.connect("lalang_db", host="localhost", port=27017)

    # check this EmbeddedDocumentList field exists before adding to it;
    # if all list items get deleted, then MongoDB will delete the list field
    # so guard against that
    assert not Student.objects(id=student_id,
                               __raw__={"language_progress": None}).first()

    # get embedded document for this student for this language
    language_embed_doc = Student.objects(
        id=student_id).first().language_progress.filter(
        language=language)

    # in case the list or queue doesn't exist
    try:
        # check if the embedded document exists and question queues
        # are not empty
        if language_embed_doc and language_embed_doc[0].f_question_queue:
            # if there are questions in queue, query and add them to list
            # pick randomly between the front and back question queues
            if random.choices([0, 1], cum_weights=[40, 100])[0]:
                side = "front"
                question_id = language_embed_doc[0].f_question_queue[0]
            else:
                side = "back"
                question_id = language_embed_doc[0].b_question_queue[0]
            return Question.objects(id=question_id).first(), side
        else:
            return None, None
    except IndexError:
        return None, None
Пример #5
0
def add_questions_to_db(db_name, language, filename):
    """Copy questions from a csv file to a MongoDB database."""
    print(sys.path)
    print(os.getcwd())

    mongoengine.connect(db_name, host="localhost", port=27017)

    with open(filename, encoding="utf8") as csv_file:
        csv_reader = csv.reader(csv_file, delimiter=",")
        column_names = next(csv_reader)

    with open(filename, encoding="utf8") as csv_file:
        csv_reader = csv.DictReader(csv_file, delimiter=",")
        for row in csv_reader:
            question = Question(description="word flashcard",
                                skill="Vocabulary",
                                language=language.lower(),
                                word=row[column_names[0]],
                                part_of_speech=row[column_names[1]],
                                audio_files=row[column_names[2]],
                                image_files=row[column_names[3]])

            question.save()
Пример #6
0

mongoengine.connect("lalang_db", host="localhost", port=27017)

# query to generate options for user input
language_in = input("What language are these questions for? ").lower()


num_questions = 5

# dummy variable
student_id = ""

query_args = {"language": f"{language_in}", "description": "word flashcard",
              "child_appropriate": True}
results_iter = Question.objects(__raw__=query_args)
total_questions = results_iter.count()

print("Total number of questions: ", total_questions)

question_set = set()
while len(question_set) < num_questions:
    question_set.add(random.randint(0, total_questions))

question_list = sorted(list(question_set))

question_list_steps = []

question_list_steps.append(question_list[0])

for i in range(1, len(question_list)):
Пример #7
0
"""

import mongoengine
import csv
import sys
import os

sys.path.append("C:\\Users\\Lukasz\\Python\\ErroresBuenos")

from lalang.db_model import Question

db_in = input("Which database should the questions be deleted from? ")
mongoengine.connect(db_in, host="localhost", port=27017)

del_match = {"word": {"$regex": "^DU"}, "language": "Polish"}
del_records_iter = Question.objects(__raw__=del_match)
num_del_records = del_records_iter.count()
if num_del_records > 0:
    deleted_counter = 0
    print(num_del_records, " records found for deletion.")
    for del_record in del_records_iter:
        del_record_contents = (
            f"{{\"word\": \"{del_record.word}\", \"description\": \"{del_record.description}\", "
            f"\"skill\": \"{del_record.skill}\", \"language\": \"{del_record.language}\"}}"
        )

        del_confirm = input("Do you want to delete record: "
                            f"{del_record_contents}? ")
        input_choices = {"yes", "y", "1"}
        if del_confirm.lower() in input_choices:
            del_record.delete()
Пример #8
0
def prep_questions(language, side, student_id, num_questions_needed):
    """Pick new questions and save them in db.

    Randomly query Question collection for more questions in the database,
    add them to student's queue in Student document - i.e. save them in db.

    Argument:

    language: str
    side: "front" or "back" - which side of the question card
    student_id = str or ObjectId() from MongoDB
    num_questions_needed: integer

    Precondition:
    num_questions_needed > 0

    Return:
    None
    """
    # set the flags for the queues and stacks, either "f" or "b"
    s = side[0]

    # set the flags for the queues and stacks from the opposite question side
    if s == "f":
        op = "b"
    else:
        op = "f"

    num_questions_added = 0
    # force to string if ObjectId passed
    student_id = str(student_id)

    mongoengine.connect("lalang_db", host="localhost", port=27017)

    query_args = {"language": f"{language}",
                  "description": "word flashcard"}
    questions_iter = Question.objects(__raw__=query_args)

    # get embedded document for this student for this language
    language_embed_doc = Student.objects(
        id=student_id).first().language_progress.filter(
        language=language)

    logging.info("Num of questions in queue at beginning of prep_questions: ")
    logging.info(len(getattr(language_embed_doc[0], f"{s}_question_queue")))

    # if answered_corr_stack is "big", reduce it, i.e. release questions
    # for review
    size_corr_stack = len(getattr(language_embed_doc[0],
                                  f"{s}_answered_corr_stack"))
    logging.info(f"size_corr_stack: {size_corr_stack}")

    if size_corr_stack > START_REVIEW:
        logging.info("We need to release questions for review")
        questions_to_release = (size_corr_stack - BASE_ANSWERED_CORRECTLY)
        logging.info(f"Number of questions to release: {questions_to_release}")
        del getattr(language_embed_doc[0],
                    f"{s}_answered_corr_stack")[:questions_to_release]
        logging.info("Questions released for review.")

    # draw random question from all possible questions
    # keep drawing questions until you get {num_questions_needed} questions
    while num_questions_added < num_questions_needed:
        logging.info("In the while loop in prep_questions")
        q_used = False
        duplicate_check_passed = False

        # for side="back", draw from three sources:
        # 25% of the time from f_answered_wrong_stack,
        # i.e. the opposite - "front" - side of the question
        # 25% of the time from b_answered_wrong_stack
        # 50% of the time from all questions in the Question collection

        # for side="front", draw from four sources:
        # 20% of the time from b_answered_wrong_stack,
        # i.e. the opposite - "back" - side of the question
        # 15% of the time from f_answered_wrong_stack
        # 50% of the time from all questions in the Question collection
        # 15% of the time from f_answered_review_stack

        choices = [0, 1, 2, 3]

        if side == "back":
            weights = [25, 50, 100, 100]
            draw_bin = random.choices(choices, cum_weights=weights)[0]
        else:
            weights = [20, 35, 85, 100]
            draw_bin = random.choices(choices, cum_weights=weights)[0]

        # if picking from all questions in the Question collection
        if draw_bin == 2:
            drawn_id = _draw_random_question(questions_iter)

        # if picking from wrong_stack from the opposite side
        if draw_bin == 0:
            # check if the opposite answered_wrong_stack is big enough
            # to draw from; if so, draw from the first 10 questions

            if (len(getattr(language_embed_doc[0], f"{op}_answered_wrong_stack"))
                    >= MIN_WRONG_STACK_SIZE_FOR_DRAW):
                pick = random.choice(range(10))
                drawn_id = getattr(language_embed_doc[0],
                                   f"{op}_answered_wrong_stack")[pick]
            else:
                # it didn't work, so just draw a random question
                # from all questions in the collection
                drawn_id = _draw_random_question(questions_iter)

        # if picking from wrong_stack from the same side
        if draw_bin == 1:
            # check if the answered_wrong_stack for the same side is big enough
            # to draw from; if so, use the first question in the stack

            if (len(getattr(language_embed_doc[0], f"{op}_answered_wrong_stack"))
                    >= MIN_WRONG_STACK_SIZE_FOR_DRAW):
                drawn_id = getattr(language_embed_doc[0],
                                   f"{op}_answered_wrong_stack").pop(0)
                # we already know that this drawn question is not present
                # in any relevant queue or stack, so it can be used.
                # So, set a flag to stop further verification.
                duplicate_check_passed = True
            else:
                # it didn't work, so just draw a random question
                # from all questions in the collection
                drawn_id = _draw_random_question(questions_iter)

        # if picking from f_answered_review_stack for "front" sided question
        if draw_bin == 3:
            # check if f_answered_review_stack is big enough to draw from;
            # if so, use the first question in the stack

            if (len(language_embed_doc[0].f_answered_review_stack)
                    >= MIN_REVIEW_STACK_SIZE_FOR_DRAW):
                drawn_id = language_embed_doc[0].f_answered_review_stack.pop(0)
                # we already know that this drawn question is not present
                # in any relevant queue or stack, so it can be used.
                # So, set a flag to stop further verification.
                duplicate_check_passed = True
            else:
                # it didn't work, so just draw a random question
                # from all questions in the collection
                drawn_id = _draw_random_question(questions_iter)

        # check that the drawn question is not in the queue, or the two stacks
        # of answered questions; if not, then add it to the queue
        if not duplicate_check_passed:
            for q_id in getattr(language_embed_doc[0], f"{s}_question_queue"):
                if drawn_id == q_id:
                    q_used = True
                    break

        if not duplicate_check_passed and not q_used:
            for q_id in getattr(language_embed_doc[0], f"{s}_answered_wrong_stack"):
                if drawn_id == q_id:
                    q_used = True
                    break
            if not q_used:
                for q_id in getattr(language_embed_doc[0], f"{s}_answered_corr_stack"):
                    if drawn_id == q_id:
                        q_used = True
                        break

        if duplicate_check_passed or not q_used:
            # question not used, so add its id to the Student queue of questions
            getattr(language_embed_doc[0], f"{s}_question_queue").append(drawn_id)
            language_embed_doc.save()
            num_questions_added += 1
            logging.info(f"Num of questions added to queue: {num_questions_added}")

    # query again to check the size of the question queue
    language_embed_doc = Student.objects(
        id=student_id).first().language_progress.filter(
        language=language)

    logging.info("Num of questions in queue at the end of prep_questions: ")
    logging.info(len(getattr(language_embed_doc[0], f"{s}_question_queue")))

    return None
Пример #9
0
def dict_to_question_obj(question_as_dict):
    """Take question represented as dictionary and return Question object."""
    q_obj = Question()
    for k, v in question_as_dict.items():
        setattr(q_obj, k, v)
    return q_obj