def on_start(submission_uuid): """ Creates a new student training workflow. This function should be called to indicate that a submission has entered the student training workflow part of the assessment process. Args: submission_uuid (str): The submission UUID for the student that is initiating training. Returns: None Raises: StudentTrainingInternalError: Raised when an error occurs persisting the Student Training Workflow """ try: StudentTrainingWorkflow.create_workflow(submission_uuid) except Exception as ex: msg = ( "An internal error has occurred while creating the learner " "training workflow for submission UUID {}".format(submission_uuid) ) logger.exception(msg) raise StudentTrainingInternalError(msg) from ex
def get_num_completed(submission_uuid): """ Get the number of training examples the student has assessed successfully. Args: submission_uuid (str): The UUID of the student's submission. Returns: int: The number of completed training examples Raises: StudentTrainingInternalError Example usage: >>> get_num_completed("5443ebbbe2297b30f503736e26be84f6c7303c57") 2 """ try: try: workflow = StudentTrainingWorkflow.objects.get(submission_uuid=submission_uuid) except StudentTrainingWorkflow.DoesNotExist: return 0 else: return workflow.num_completed except DatabaseError as ex: msg = ( "An unexpected error occurred while " "retrieving the learner training workflow status for submission UUID {}" ).format(submission_uuid) logger.exception(msg) raise StudentTrainingInternalError(msg) from ex
def assess_training_example(submission_uuid, options_selected, update_workflow=True): """ Assess a training example and update the workflow. This must be called *after* `get_training_example()`. Args: submission_uuid (str): The UUID of the student's submission. options_selected (dict): The options the student selected. Keyword Arguments: update_workflow (bool): If true, mark the current item complete if the student has assessed the example correctly. Returns: corrections (dict): Dictionary containing the correct options for criteria the student scored incorrectly. Raises: StudentTrainingRequestError StudentTrainingInternalError Example usage: >>> options_selected = { >>> 'vocabulary': 'good', >>> 'grammar': 'excellent' >>> } >>> assess_training_example("5443ebbbe2297b30f503736e26be84f6c7303c57", options_selected) {'grammar': 'poor'} """ # Find a workflow for the student try: workflow = StudentTrainingWorkflow.objects.get(submission_uuid=submission_uuid) # Find the item the student is currently working on item = workflow.current_item if item is None: msg = ( "No items are available in the learner training workflow associated with " "submission UUID {}" ).format(submission_uuid) raise StudentTrainingRequestError(msg) # Check the student's scores against the staff's scores. corrections = item.check_options(options_selected) # Mark the item as complete if the student's selection # matches the instructor's selection if update_workflow and not corrections: item.mark_complete() return corrections except StudentTrainingWorkflow.DoesNotExist as ex: msg = "Could not find learner training workflow for submission UUID {}".format(submission_uuid) raise StudentTrainingRequestError(msg) from ex except DatabaseError as ex: msg = ( "An error occurred while comparing the learner's assessment " "to the training example. The submission UUID for the learner is {}" ).format(submission_uuid) logger.exception(msg) raise StudentTrainingInternalError(msg) from ex
def get_training_example(submission_uuid, rubric, examples): """ Retrieve a training example for the student to assess. This will implicitly create a workflow for the student if one does not yet exist. NOTE: We include the rubric in the returned dictionary to handle the case in which the instructor changes the rubric definition while the student is assessing the training example. Once a student starts on a training example, the student should see the same training example consistently. However, the next training example the student retrieves will use the updated rubric. Args: submission_uuid (str): The UUID of the student's submission. rubric (dict): Serialized rubric model. examples (list): List of serialized training examples. Returns: dict: The training example with keys "answer", "rubric", and "options_selected". If no training examples are available (the student has already assessed every example, or no examples are defined), returns None. Raises: StudentTrainingInternalError Example usage: >>> examples = [ >>> { >>> 'answer': { >>> 'parts': { >>> [ >>> {'text:' 'Answer part 1'}, >>> {'text:' 'Answer part 2'}, >>> {'text:' 'Answer part 3'} >>> ] >>> } >>> }, >>> 'options_selected': { >>> 'vocabulary': 'good', >>> 'grammar': 'poor' >>> } >>> } >>> ] >>> >>> get_training_example("5443ebbbe2297b30f503736e26be84f6c7303c57", rubric, examples) { 'answer': { 'parts': { [ {'text:' 'Answer part 1'}, {'text:' 'Answer part 2'}, {'text:' 'Answer part 3'} ] } }, 'rubric': { "prompts": [ {"description": "Prompt 1"}, {"description": "Prompt 2"}, {"description": "Prompt 3"} ], "criteria": [ { "order_num": 0, "name": "vocabulary", "prompt": "How varied is the vocabulary?", "options": options }, { "order_num": 1, "name": "grammar", "prompt": "How correct is the grammar?", "options": options } ], }, 'options_selected': { 'vocabulary': 'good', 'grammar': 'excellent' } } """ try: # Validate the training examples errors = validate_training_examples(rubric, examples) if errors: msg = ( "Training examples do not match the rubric (submission UUID is {uuid}): {errors}" ).format(uuid=submission_uuid, errors="\n".join(errors)) raise StudentTrainingRequestError(msg) # Get or create the workflow workflow = StudentTrainingWorkflow.get_workflow(submission_uuid=submission_uuid) if not workflow: raise StudentTrainingRequestError( u"No learner training workflow found for submission {}".format(submission_uuid) ) # Get or create the training examples examples = deserialize_training_examples(examples, rubric) # Pick a training example that the student has not yet completed # If the student already started a training example, then return that instead. next_example = workflow.next_training_example(examples) return None if next_example is None else serialize_training_example(next_example) except (InvalidRubric, InvalidRubricSelection, InvalidTrainingExample) as ex: logger.exception( u"Could not deserialize training examples for submission UUID {}".format(submission_uuid) ) raise StudentTrainingRequestError(ex) from ex except sub_api.SubmissionNotFoundError as ex: msg = u"Could not retrieve the submission with UUID {}".format(submission_uuid) logger.exception(msg) raise StudentTrainingRequestError(msg) from ex except DatabaseError as ex: msg = ( u"Could not retrieve a training example for the learner with submission UUID {}" ).format(submission_uuid) logger.exception(msg) raise StudentTrainingInternalError(msg) from ex