diff --git a/wavefront/server/modules/gold_module/gold_module/controllers/image_controller.py b/wavefront/server/modules/gold_module/gold_module/controllers/image_controller.py index 512227a9..6b1eff07 100644 --- a/wavefront/server/modules/gold_module/gold_module/controllers/image_controller.py +++ b/wavefront/server/modules/gold_module/gold_module/controllers/image_controller.py @@ -13,7 +13,10 @@ from fastapi.responses import JSONResponse from gold_module.gold_container import GoldContainer from gold_module.services.image_service import ImageService -from gold_module.models.gold_image_request import ImageAnalysisRequest +from gold_module.models.gold_image_request import ( + ImageAnalysisRequest, + AdhocImageUploadRequest, +) image_controller = APIRouter() @@ -88,3 +91,68 @@ async def process_image( status_code=status.HTTP_200_OK, content=response_formatter.buildSuccessResponse(result), ) + + +@image_controller.post('/historical_images') +@inject +async def upload_historical_images( + request: AdhocImageUploadRequest, + image_service: ImageService = Depends(Provide[GoldContainer.image_service]), + response_formatter: ResponseFormatter = Depends( + Provide[CommonContainer.response_formatter] + ), +): + image_str = request.image + image_name = request.loan_id + + gold_image = None + # Check for data URL (base64 with MIME) + data_url_pattern = r'^data:(image/\w+);base64,(.+)' + match = re.match(data_url_pattern, image_str) + if match: + try: + gold_image = base64.b64decode(match.group(2)) + except Exception: + return JSONResponse( + status_code=status.HTTP_400_BAD_REQUEST, + content=response_formatter.buildErrorResponse( + 'Invalid base64 image encoding' + ), + ) + elif image_str.startswith('http://') or image_str.startswith('https://'): + # Download the image from the URL + try: + async with httpx.AsyncClient() as client: + resp = await client.get(image_str) + if resp.status_code != 200: + return JSONResponse( + status_code=status.HTTP_400_BAD_REQUEST, + content=response_formatter.buildErrorResponse( + 'Failed to download image from URL' + ), + ) + gold_image = resp.content + except Exception: + return JSONResponse( + status_code=status.HTTP_400_BAD_REQUEST, + content=response_formatter.buildErrorResponse( + 'Error downloading image from URL' + ), + ) + else: + return JSONResponse( + status_code=status.HTTP_400_BAD_REQUEST, + content=response_formatter.buildErrorResponse( + 'Image must be a data URL or a direct image URL' + ), + ) + if not gold_image: + return JSONResponse( + status_code=status.HTTP_400_BAD_REQUEST, + content=response_formatter.buildErrorResponse('Empty image file'), + ) + result = await image_service.save_image(gold_image, image_name) + return JSONResponse( + status_code=status.HTTP_200_OK, + content=response_formatter.buildSuccessResponse(result), + ) diff --git a/wavefront/server/modules/gold_module/gold_module/models/gold_image_request.py b/wavefront/server/modules/gold_module/gold_module/models/gold_image_request.py index db4e0627..7afe5ca9 100644 --- a/wavefront/server/modules/gold_module/gold_module/models/gold_image_request.py +++ b/wavefront/server/modules/gold_module/gold_module/models/gold_image_request.py @@ -87,3 +87,8 @@ def to_str_recursive(val): class ImageAnalysisRequest(BaseModel): image: str # data URL (base64 with MIME) or direct URL metadata: ImageMetadata + + +class AdhocImageUploadRequest(BaseModel): + image: str + loan_id: str diff --git a/wavefront/server/modules/gold_module/gold_module/services/cloud_image_service.py b/wavefront/server/modules/gold_module/gold_module/services/cloud_image_service.py index 404f6d00..188b4b4c 100644 --- a/wavefront/server/modules/gold_module/gold_module/services/cloud_image_service.py +++ b/wavefront/server/modules/gold_module/gold_module/services/cloud_image_service.py @@ -20,7 +20,7 @@ async def send_message(self, message: Dict[str, Any]) -> str: @abstractmethod async def upload_image_metadata( - self, image_metadata: bytes, object_key: str + self, image_metadata: bytes | str, object_key: str ) -> Tuple[str, str]: """Upload image metadata to the cloud storage""" pass diff --git a/wavefront/server/modules/gold_module/gold_module/services/image_service.py b/wavefront/server/modules/gold_module/gold_module/services/image_service.py index 4e6c80ef..e12c3150 100644 --- a/wavefront/server/modules/gold_module/gold_module/services/image_service.py +++ b/wavefront/server/modules/gold_module/gold_module/services/image_service.py @@ -13,6 +13,13 @@ class ImageService: def __init__(self, cloud_service: CloudImageService): self.cloud_service = cloud_service + async def save_image(self, image_data: bytes, image_name: str): + validated_image_data = await self._validate_image(image_data) + + bucket_name, file_path = await self.cloud_service.upload_image( + validated_image_data, f'historical_data/{image_name}' + ) + async def process_image( self, image_data: bytes, metadata: Dict[str, Any] ) -> Dict[str, Any]: @@ -61,7 +68,6 @@ async def _validate_image(self, image_data: bytes) -> bytes: img_format = img.format if img.format else 'JPEG' img.save(buffer, format=img_format, quality=85) return buffer.getvalue() - except Exception as e: logger.error(f'Error validating image: {str(e)}') raise ValueError(f'Invalid image data: {str(e)}')