def construct_model_out(m_v, structure, segment_result): ''' Construct ModelOutput protobuf message object using segmentation results. Parameters: m_v - django.db.ModelVersion - Database model entry for model version structure - django.db.Structure - Databse model entry for the structure corresponding to the model version. segment_result - [ndarray] - List of output channel data in ndarray form Returns: model_out - ModelOutput.pb - Protobuf message object for the model output ''' model_out = Model_pb2.ModelOutput() model_out.ModelID = m_v.model_version_id model_out.ProcesserVersion = "{}.{}".format(m_v.major_version, \ m_v.minor_version) model_out.LanguageCode = m_v.language_code structure_pb = structure.model_to_pb() for result in segment_result: out_channel = Model_pb2.ModelOutputChannel() out_channel.Structure.CopyFrom(structure_pb) depth, height, width = result.shape out_channel.Volume.Width = width out_channel.Volume.Height = height out_channel.Volume.Depth = depth result_bytes = result.tobytes() out = BytesIO() with gzip.GzipFile(fileobj=out, mode='w') as file_out: file_out.write(result_bytes) out_channel.Volume.Data = out.getvalue() out_channel.Volume.DataType = Primitives3D_pb2.VolumeData3D.DataTypes.Byte out_channel.Volume.CompressionMethod = 0 model_out.Channels.append(out_channel) return model_out
def get_segmentation_result(request, model_id, segmentation_id): ''' Endpoint for API GET Segmentation Job result requests. Parameters: model_id (str) - model_id with which the segmentation job should use. segmentation_id (str) - UUID str for the segmentation job Returns: 1. ModelOutput protobuf message if "accept" header is "application/x-protobuf" 2. JSON response otherwise ''' # Database query for segmentation job with segmentation_id parameter. try: seg_job = SegmentationJob.objects.get(model_id=model_id, segmentation_id=segmentation_id) except: msg = "Invalid request." details = "The segmentation job does not exist." return bad_request_helper(request, msg, details, 400) job_status = seg_job.get_job_progress() # Return unfinished bad request if progress isn't 100. if job_status.Progress < 100: msg = "Invalid request." details = "The segmentation job is still processing." return bad_request_helper(request, msg, details, 400) try: # Attempts to read the file as bytestring model_out_path = seg_job.model_output.path f_in = open(model_out_path, 'rb') model_out = f_in.read() f_in.close() if request.headers["accept"] == "application/x-protobuf": seg_job.delete() return HttpResponse(model_out, status=200) # Else response = Model_pb2.ModelOutput() response.ParseFromString(model_out) seg_job.delete() return JsonResponse(json_format.MessageToDict(response), status=200) except: msg = "Invalid request." details = "The segmentation job has encountered an error." return bad_request_helper(request, msg, details, 400)
def test_post_job_retrieve_results_protobuf(self): ''' Test for endpoints: /api/v2/Model/{modelId}/segmentation /api/v2/Model/{modelId}/segmentation/{segmentationId} /api/v2/Model/{modelId}/segmentation/{segmentationId}/result Since database objects are not maintained between test cases, 3 end-points are tested here. Retrieve protobuf results ''' #---------------------------------------------------------------------- # Testing POST /api/v2/Model/{modelId}/segmentation #---------------------------------------------------------------------- # Post job to temporary server model_id = PostSegmentationTestCase.model_version.model_version_id.replace(" ", "%20") post_response = self.client.post('/api/v2/Model/{}/segmentation'.format(model_id), \ self.seg_job, \ content_type='application/x-protobuf', \ **{'HTTP_ACCEPT':'application/x-protobuf'}) self.assertEqual(post_response.status_code, 200, \ msg='/api/v2/Model/{}/segmentation endpoint did not return 200 status code.'.format(\ model_id)) # Append orphaned segmentation job file path to path list for teardown. db_seg_path = SegmentationJob.objects.all()[0].model_input.path self.path_list.append(db_seg_path) # Parse protobuf message output seg_task = Model_pb2.SegmentationTask() seg_task.ParseFromString(post_response.content) seg_id = seg_task.SegmentationID #---------------------------------------------------------------------- # Testing /api/v2/Model/{modelId}/segmentation/{segmentationId} #---------------------------------------------------------------------- # Get progress from temporary server. Since the test client is running with eager Celery # scheduling, it should always return 100% progress. get_response = self.client.get('/api/v2/Model/{}/segmentation/{}'.format( \ model_id, seg_id), \ **{'HTTP_ACCEPT':'application/x-protobuf'}) self.assertEqual(get_response.status_code, 200, \ msg='/api/v2/Model/{}/segmentation/{} endpoint did not return 200 status code.'.format(\ model_id, seg_id)) # Parse protobuf message output progress = Model_pb2.SegmentationProgress() progress.ParseFromString(get_response.content) self.assertEqual(progress.Progress, 100, \ msg='/api/v2/Model/{}/segmentation/{} endpoint did not return 100% progress.'.format(\ model_id, seg_id)) # Append orphaned segmentation job file path to path list for teardown. db_results_path = SegmentationJob.objects.all()[0].model_output.path self.path_list.append(db_results_path) #---------------------------------------------------------------------- # Testing /api/v2/Model/{modelId}/segmentation/{segmentationId}/result #---------------------------------------------------------------------- seg_response = self.client.get('/api/v2/Model/{}/segmentation/{}/result'.format( \ model_id, seg_id), \ **{'HTTP_ACCEPT':'application/x-protobuf'}) self.assertEqual(seg_response.status_code, 200, \ msg='/api/v2/Model/{}/segmentation/{}/result endpoint did not return 200 status code.'\ .format(model_id, seg_id)) seg_result = Model_pb2.ModelOutput() seg_result.ParseFromString(seg_response.content) self.assertEqual(seg_result.ModelID, model_id.replace("%20"," "), \ msg='/api/v2/Model/{}/segmentation/{}/result endpoint did not fetch correct result.'\ .format(model_id, seg_id))