def test_store_classifier_data(self): """Test the store_classifier_data method.""" exp_id = u'1' next_scheduled_check_time = datetime.datetime.utcnow() state_name = 'Home' interaction_id = 'TextInput' job_id = self._create_classifier_training_job( feconf.INTERACTION_CLASSIFIER_MAPPING['TextInput']['algorithm_id'], interaction_id, exp_id, 1, next_scheduled_check_time, [], state_name, feconf.TRAINING_JOB_STATUS_PENDING, {}, 1) # Retrieve classifier data from GCS and ensure that content is same. classifier_training_job = ( classifier_services.get_classifier_training_job_by_id(job_id)) classifier_data = ( self._get_classifier_data_from_classifier_training_job( classifier_training_job)) self.assertEqual(json.loads(classifier_data.model_json), {}) classifier_data_proto = text_classifier_pb2.TextClassifierFrozenModel() classifier_data_proto.model_json = json.dumps( {'classifier_data': 'data'}) classifier_services.store_classifier_data(job_id, classifier_data_proto) classifier_training_job = ( classifier_services.get_classifier_training_job_by_id(job_id)) classifier_data = ( self._get_classifier_data_from_classifier_training_job( classifier_training_job)) self.assertDictEqual(json.loads(classifier_data.model_json), {'classifier_data': 'data'})
def post(self): """Handles POST requests.""" payload_proto = ( training_job_response_payload_pb2.TrainingJobResponsePayload()) payload_proto.ParseFromString(self.request.body) if not validate_job_result_message_proto(payload_proto.job_result): raise self.InvalidInputException job_id = payload_proto.job_result.job_id classifier_training_job = ( classifier_services.get_classifier_training_job_by_id(job_id)) if classifier_training_job.status == ( feconf.TRAINING_JOB_STATUS_FAILED): # Send email to admin and admin-specified email recipients. # Other email recipients are specified on admin config page. email_manager.send_job_failure_email(job_id) raise self.InternalErrorException( 'The current status of the job cannot transition to COMPLETE.') classifier_data_proto = getattr( payload_proto.job_result, payload_proto.job_result.WhichOneof('classifier_frozen_model')) classifier_services.store_classifier_data( job_id, classifier_data_proto) # Update status of the training job to 'COMPLETE'. classifier_services.mark_training_job_complete(job_id) return self.render_json({})
def post(self): """Handles POST requests.""" signature = self.payload.get('signature') message = self.payload.get('message') vm_id = self.payload.get('vm_id') if vm_id == feconf.DEFAULT_VM_ID and not feconf.DEV_MODE: raise self.UnauthorizedUserException if not validate_job_result_message_dict(message): raise self.InvalidInputException if not verify_signature(message, vm_id, signature): raise self.UnauthorizedUserException job_id = message['job_id'] classifier_data = message['classifier_data'] classifier_training_job = ( classifier_services.get_classifier_training_job_by_id(job_id)) if classifier_training_job.status == ( feconf.TRAINING_JOB_STATUS_FAILED): raise self.InternalErrorException( 'The current status of the job cannot transition to COMPLETE.') try: classifier_services.store_classifier_data(job_id, classifier_data) except Exception as e: raise self.InternalErrorException(e) # Update status of the training job to 'COMPLETE'. classifier_services.mark_training_job_complete(job_id) return self.render_json({})
def post(self): """Handles POST requests.""" signature = self.payload.get('signature') message = self.payload.get('message') vm_id = self.payload.get('vm_id') if vm_id == feconf.DEFAULT_VM_ID and not constants.DEV_MODE: raise self.UnauthorizedUserException if not validate_job_result_message_dict(message): raise self.InvalidInputException if not verify_signature(message, vm_id, signature): raise self.UnauthorizedUserException job_id = message['job_id'] # The classifier data received in the payload has all floating point # values stored as strings. This is because floating point numbers # are represented differently on GAE(Oppia) and GCE(Oppia-ml). # Therefore, converting all floating point numbers to string keeps # signature consistent on both Oppia and Oppia-ml. # For more info visit: https://stackoverflow.com/q/40173295 classifier_data = ( classifier_services. convert_strings_to_float_numbers_in_classifier_data( #pylint: disable=line-too-long message['classifier_data_with_floats_stringified'])) classifier_training_job = ( classifier_services.get_classifier_training_job_by_id(job_id)) if classifier_training_job.status == ( feconf.TRAINING_JOB_STATUS_FAILED): # Send email to admin and admin-specified email recipients. # Other email recipients are specified on admin config page. email_manager.send_job_failure_email(job_id) raise self.InternalErrorException( 'The current status of the job cannot transition to COMPLETE.') try: classifier_services.store_classifier_data(job_id, classifier_data) except Exception as e: raise self.InternalErrorException(e) # Update status of the training job to 'COMPLETE'. classifier_services.mark_training_job_complete(job_id) return self.render_json({})
def test_creation_of_state_classifier_mapping(self): super(ExplorationStateClassifierMappingTests, self).setUp() exploration_id = '15' self.login(self.VIEWER_EMAIL) self.signup(self.VIEWER_EMAIL, self.VIEWER_USERNAME) exp_services.delete_demo(exploration_id) # We enable ENABLE_ML_CLASSIFIERS so that the subsequent call to # save_exploration handles job creation for trainable states. # Since only one demo exploration has a trainable state, we modify our # values for MIN_ASSIGNED_LABELS and MIN_TOTAL_TRAINING_EXAMPLES to let # the classifier_demo_exploration.yaml be trainable. This is # completely for testing purposes. with self.swap(feconf, 'ENABLE_ML_CLASSIFIERS', True): with self.swap(feconf, 'MIN_TOTAL_TRAINING_EXAMPLES', 5): with self.swap(feconf, 'MIN_ASSIGNED_LABELS', 1): exp_services.load_demo(exploration_id) # Retrieve job_id of created job (because of save_exp). all_jobs = classifier_models.ClassifierTrainingJobModel.get_all() self.assertEqual(all_jobs.count(), 1) for job in all_jobs: job_id = job.id classifier_services.store_classifier_data(job_id, {}) expected_state_classifier_mapping = { 'text': { 'algorithm_id': 'LDAStringClassifier', 'classifier_data': {}, 'data_schema_version': 1 } } # Call the handler. exploration_dict = self.get_json( '%s/%s' % (feconf.EXPLORATION_INIT_URL_PREFIX, exploration_id)) retrieved_state_classifier_mapping = exploration_dict[ 'state_classifier_mapping'] self.assertEqual(expected_state_classifier_mapping, retrieved_state_classifier_mapping)
def test_store_classifier_data(self): """Test the store_classifier_data method.""" exp_id = u'1' next_scheduled_check_time = datetime.datetime.utcnow() state_name = 'Home' interaction_id = 'TextInput' job_id = classifier_models.ClassifierTrainingJobModel.create( feconf.INTERACTION_CLASSIFIER_MAPPING['TextInput']['algorithm_id'], interaction_id, exp_id, 1, next_scheduled_check_time, [], state_name, feconf.TRAINING_JOB_STATUS_PENDING, None, 1) classifier_training_job = ( classifier_services.get_classifier_training_job_by_id(job_id)) self.assertEqual(classifier_training_job.classifier_data, None) classifier_services.store_classifier_data(job_id, {}) classifier_training_job = ( classifier_services.get_classifier_training_job_by_id(job_id)) self.assertEqual(classifier_training_job.classifier_data, {})
def test_can_not_store_classifier_data_due_to_invalid_job_id(self): with self.assertRaisesRegexp( Exception, 'The ClassifierTrainingJobModel corresponding to the ' 'job_id of the ClassifierTrainingJob does not exist.'): classifier_services.store_classifier_data('invalid_job_id', {})