def test_training_job_migration_on_algorithm_version_change(self): self.post_blob( '/ml/trainedclassifierhandler', self.payload_proto.SerializeToString(), expected_status_int=200) params = { 'exploration_id': self.exp_id, 'exploration_version': self.exploration.version, 'state_name': 'Home', } interaction_classifier_mapping = { 'TextInput': { 'algorithm_id': 'TextClassifier', 'algorithm_version': 2 }, } with self.swap( feconf, 'INTERACTION_CLASSIFIER_MAPPING', interaction_classifier_mapping): self.get_json( '/ml/trainedclassifierhandler', params=params, expected_status_int=404) state_training_jobs_mapping = ( classifier_services.get_state_training_jobs_mapping( self.exp_id, self.exploration.version, 'Home')) self.assertIn( 'TextClassifier', state_training_jobs_mapping.algorithm_ids_to_job_ids) with self.swap( feconf, 'INTERACTION_CLASSIFIER_MAPPING', interaction_classifier_mapping): json_response = self.post_json( '/ml/nextjobhandler', self.payload_for_fetching_next_job_request, expected_status_int=200) self.assertEqual( state_training_jobs_mapping.algorithm_ids_to_job_ids[ 'TextClassifier'], json_response['job_id'] ) self.assertEqual(json_response['algorithm_id'], 'TextClassifier') self.assertEqual(json_response['algorithm_version'], 2)
def get(self): """Handles GET requests. Retrieves the name of the file on GCS storing the trained model parameters and transfers it to the frontend. """ exploration_id = self.normalized_request.get('exploration_id') state_name = self.normalized_request.get('state_name') try: exp_version = int(self.normalized_request.get( 'exploration_version')) exploration = exp_fetchers.get_exploration_by_id( exploration_id, version=exp_version) interaction_id = exploration.states[state_name].interaction.id except: raise self.InvalidInputException( 'Entity for exploration with id %s, version %s and state %s ' 'not found.' % ( exploration_id, self.normalized_request.get( 'exploration_version'), state_name)) if interaction_id not in feconf.INTERACTION_CLASSIFIER_MAPPING: raise self.PageNotFoundException( 'No classifier algorithm found for %s interaction' % ( interaction_id)) algorithm_id = feconf.INTERACTION_CLASSIFIER_MAPPING[ interaction_id]['algorithm_id'] algorithm_version = feconf.INTERACTION_CLASSIFIER_MAPPING[ interaction_id]['algorithm_version'] state_training_jobs_mapping = ( classifier_services.get_state_training_jobs_mapping( exploration_id, exp_version, state_name)) if state_training_jobs_mapping is None: raise self.InvalidInputException( 'No training jobs exist for given exploration state') if not ( algorithm_id in state_training_jobs_mapping. algorithm_ids_to_job_ids): classifier_services.migrate_state_training_jobs( state_training_jobs_mapping) # Since the required training job doesn't exist and old job has to # be migrated, a PageNotFound exception is raised. # Once jobs are migrated and trained they can be sent to the client # upon further requests. This exception should be gracefully # handled in the client code and shouldn't break UX. raise self.PageNotFoundException( 'No valid classifier exists for the given exploration state') training_job = classifier_services.get_classifier_training_job_by_id( state_training_jobs_mapping.algorithm_ids_to_job_ids[algorithm_id]) if training_job is None or ( training_job.status != feconf.TRAINING_JOB_STATUS_COMPLETE): raise self.PageNotFoundException( 'No valid classifier exists for the given exploration state') if training_job.algorithm_version != algorithm_version: classifier_services.migrate_state_training_jobs( state_training_jobs_mapping) # Since the required training job doesn't exist and old job has to # be migrated, a PageNotFound exception is raised. # Once jobs are migrated and trained they can be sent to the client # upon further requests. This exception should be gracefully # handled in the client code and shouldn't break UX. raise self.PageNotFoundException( 'No valid classifier exists for the given exploration state') return self.render_json({ 'algorithm_id': algorithm_id, 'algorithm_version': algorithm_version, 'gcs_filename': training_job.classifier_data_filename })