retuve.app.routes.models
The Models API for Retuve.
1# Copyright 2024 Adam McArthur 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15""" 16The Models API for Retuve. 17""" 18 19import shutil 20import tempfile 21import traceback 22from typing import Optional 23 24from fastapi import APIRouter, File, Form, HTTPException, Request, UploadFile 25 26from retuve import __version__ as retuve_version 27from retuve.app.classes import Metric2D, Metric3D, ModelResponse 28from retuve.app.helpers import ( 29 RESULTS_DIR, 30 RESULTS_URL_ACCESS, 31 analyze_validation, 32) 33from retuve.funcs import retuve_run 34from retuve.keyphrases.config import Config 35 36router = APIRouter() 37 38 39@router.post( 40 "/api/model/", 41 response_model=ModelResponse, 42 responses={ 43 400: {"description": "Invalid file type. Expected a DICOM file."}, 44 500: {"description": "Internal Server Error"}, 45 }, 46) 47def analyse_image( 48 request: Request, 49 file: UploadFile = File(...), 50 keyphrase: str = Form(...), 51 api_token: Optional[str] = Form(None), 52): 53 """ 54 Analyze a file with a Retuve Model based on the keyphrase provided. 55 56 :param request: The request object. 57 :param file: The file to be analyzed. 58 :param keyphrase: The keyphrase to be used for analysis. 59 :param api_token: The API token for the keyphrase. 60 61 :raises HTTPException: If the file or keyphrase is invalid. 62 """ 63 64 try: 65 config = Config.get_config(keyphrase) 66 67 hippa_logger = request.app.config[config.name].hippa_logger 68 69 analyze_validation(file, keyphrase, api_token) 70 71 hippa_logger.info( 72 f"Validated and Uploaded {file.filename} " 73 f"with keyphrase {keyphrase} from host: {request.client.host}." 74 ) 75 76 file_name = file.filename.split("/")[-1] 77 78 # save file in tempfile with same name 79 with tempfile.NamedTemporaryFile( 80 mode="wb", delete=False, suffix=file_name, prefix="" 81 ) as temp_file: 82 # save the file 83 shutil.copyfileobj(file.file, temp_file) 84 temp_file.flush() 85 86 # get the file location 87 temp_file = temp_file.name 88 89 result = retuve_run( 90 hip_mode=config.batch.hip_mode, 91 config=config, 92 modes_func=config.batch.mode_func, 93 modes_func_kwargs_dict=config.batch.mode_func_args, 94 file=temp_file, 95 ) 96 97 notes = "" 98 metrics3d = [] 99 metrics2d = [] 100 video_path = None 101 figure_path = None 102 img_path = None 103 104 filename = file.filename.split("/")[-1].split(".")[0] 105 106 if result.video_clip: 107 video_path = f"{RESULTS_DIR}/{filename}.mp4" 108 result.video_clip.write_videofile(video_path) 109 video_path = video_path.replace( 110 RESULTS_DIR, f"{RESULTS_URL_ACCESS}/{config.name}" 111 ) 112 113 if result.visual_3d: 114 figure_path = f"{RESULTS_DIR}/{filename}.html" 115 result.visual_3d.write_html(figure_path) 116 figure_path = figure_path.replace( 117 RESULTS_DIR, f"{RESULTS_URL_ACCESS}/{config.name}" 118 ) 119 120 if result.image: 121 img_path = f"{RESULTS_DIR}/{filename}.jpg" 122 result.image.save(img_path) 123 img_path = img_path.replace( 124 RESULTS_DIR, f"{RESULTS_URL_ACCESS}/{config.name}" 125 ) 126 127 if result.hip_datas: 128 for i, metric in enumerate(result.hip_datas.metrics): 129 metrics3d.append( 130 Metric3D( 131 name=metric.name, 132 post=0 if metric.post == "N/A" else metric.post, 133 graf=0 if metric.graf == "N/A" else metric.graf, 134 ant=0 if metric.ant == "N/A" else metric.ant, 135 full=0 if metric.full == "N/A" else metric.full, 136 ) 137 ) 138 139 notes = str(result.hip_datas.recorded_error) 140 141 if result.image: 142 for i, metric in enumerate(result.hip.metrics): 143 metrics2d.append( 144 Metric2D(name=metric.name, value=metric.value) 145 ) 146 147 # Mark success in hippa logs 148 hippa_logger.info( 149 f"Successfully processed {file.filename} with keyphrase {keyphrase} " 150 f"from host: {request.client.host}." 151 ) 152 153 # Mock response for demonstration 154 return ModelResponse( 155 notes=notes, 156 metrics_3d=metrics3d, 157 video_url=f"{config.api.url}{video_path}" if video_path else "", 158 figure_url=f"{config.api.url}{figure_path}" if figure_path else "", 159 img_url=f"{config.api.url}{img_path}" if img_path else "", 160 retuve_version=retuve_version, 161 keyphrase_name=config.name, 162 metrics_2d=metrics2d, 163 ) 164 except Exception as e: 165 # print traceback to hippa logs 166 hippa_logger.error( 167 f"Error in processing {file.filename} with keyphrase {keyphrase} " 168 f"from host: {request.client.host}." 169 ) 170 hippa_logger.error(traceback.format_exc()) 171 raise HTTPException( 172 status_code=500, detail="Internal Server Error, check logs." 173 )
router =
<fastapi.routing.APIRouter object>
@router.post('/api/model/', response_model=ModelResponse, responses={400: {'description': 'Invalid file type. Expected a DICOM file.'}, 500: {'description': 'Internal Server Error'}})
def
analyse_image( request: starlette.requests.Request, file: fastapi.datastructures.UploadFile = File(PydanticUndefined), keyphrase: str = Form(PydanticUndefined), api_token: Optional[str] = Form(None)):
40@router.post( 41 "/api/model/", 42 response_model=ModelResponse, 43 responses={ 44 400: {"description": "Invalid file type. Expected a DICOM file."}, 45 500: {"description": "Internal Server Error"}, 46 }, 47) 48def analyse_image( 49 request: Request, 50 file: UploadFile = File(...), 51 keyphrase: str = Form(...), 52 api_token: Optional[str] = Form(None), 53): 54 """ 55 Analyze a file with a Retuve Model based on the keyphrase provided. 56 57 :param request: The request object. 58 :param file: The file to be analyzed. 59 :param keyphrase: The keyphrase to be used for analysis. 60 :param api_token: The API token for the keyphrase. 61 62 :raises HTTPException: If the file or keyphrase is invalid. 63 """ 64 65 try: 66 config = Config.get_config(keyphrase) 67 68 hippa_logger = request.app.config[config.name].hippa_logger 69 70 analyze_validation(file, keyphrase, api_token) 71 72 hippa_logger.info( 73 f"Validated and Uploaded {file.filename} " 74 f"with keyphrase {keyphrase} from host: {request.client.host}." 75 ) 76 77 file_name = file.filename.split("/")[-1] 78 79 # save file in tempfile with same name 80 with tempfile.NamedTemporaryFile( 81 mode="wb", delete=False, suffix=file_name, prefix="" 82 ) as temp_file: 83 # save the file 84 shutil.copyfileobj(file.file, temp_file) 85 temp_file.flush() 86 87 # get the file location 88 temp_file = temp_file.name 89 90 result = retuve_run( 91 hip_mode=config.batch.hip_mode, 92 config=config, 93 modes_func=config.batch.mode_func, 94 modes_func_kwargs_dict=config.batch.mode_func_args, 95 file=temp_file, 96 ) 97 98 notes = "" 99 metrics3d = [] 100 metrics2d = [] 101 video_path = None 102 figure_path = None 103 img_path = None 104 105 filename = file.filename.split("/")[-1].split(".")[0] 106 107 if result.video_clip: 108 video_path = f"{RESULTS_DIR}/{filename}.mp4" 109 result.video_clip.write_videofile(video_path) 110 video_path = video_path.replace( 111 RESULTS_DIR, f"{RESULTS_URL_ACCESS}/{config.name}" 112 ) 113 114 if result.visual_3d: 115 figure_path = f"{RESULTS_DIR}/{filename}.html" 116 result.visual_3d.write_html(figure_path) 117 figure_path = figure_path.replace( 118 RESULTS_DIR, f"{RESULTS_URL_ACCESS}/{config.name}" 119 ) 120 121 if result.image: 122 img_path = f"{RESULTS_DIR}/{filename}.jpg" 123 result.image.save(img_path) 124 img_path = img_path.replace( 125 RESULTS_DIR, f"{RESULTS_URL_ACCESS}/{config.name}" 126 ) 127 128 if result.hip_datas: 129 for i, metric in enumerate(result.hip_datas.metrics): 130 metrics3d.append( 131 Metric3D( 132 name=metric.name, 133 post=0 if metric.post == "N/A" else metric.post, 134 graf=0 if metric.graf == "N/A" else metric.graf, 135 ant=0 if metric.ant == "N/A" else metric.ant, 136 full=0 if metric.full == "N/A" else metric.full, 137 ) 138 ) 139 140 notes = str(result.hip_datas.recorded_error) 141 142 if result.image: 143 for i, metric in enumerate(result.hip.metrics): 144 metrics2d.append( 145 Metric2D(name=metric.name, value=metric.value) 146 ) 147 148 # Mark success in hippa logs 149 hippa_logger.info( 150 f"Successfully processed {file.filename} with keyphrase {keyphrase} " 151 f"from host: {request.client.host}." 152 ) 153 154 # Mock response for demonstration 155 return ModelResponse( 156 notes=notes, 157 metrics_3d=metrics3d, 158 video_url=f"{config.api.url}{video_path}" if video_path else "", 159 figure_url=f"{config.api.url}{figure_path}" if figure_path else "", 160 img_url=f"{config.api.url}{img_path}" if img_path else "", 161 retuve_version=retuve_version, 162 keyphrase_name=config.name, 163 metrics_2d=metrics2d, 164 ) 165 except Exception as e: 166 # print traceback to hippa logs 167 hippa_logger.error( 168 f"Error in processing {file.filename} with keyphrase {keyphrase} " 169 f"from host: {request.client.host}." 170 ) 171 hippa_logger.error(traceback.format_exc()) 172 raise HTTPException( 173 status_code=500, detail="Internal Server Error, check logs." 174 )
Analyze a file with a Retuve Model based on the keyphrase provided.
Parameters
- request: The request object.
- file: The file to be analyzed.
- keyphrase: The keyphrase to be used for analysis.
- api_token: The API token for the keyphrase.
Raises
- HTTPException: If the file or keyphrase is invalid.