# interface/utils.py from typing import Tuple, List import os from PIL import Image class InputValidator: # Constants for validation MAX_QUERY_LENGTH = 500 MIN_IMAGES = 1 MAX_IMAGES = 10 ALLOWED_IMAGE_TYPES = ['.jpg', '.jpeg', '.png'] MAX_IMAGE_SIZE_MB = 5 MAX_IMAGE_RESOLUTION = (2048, 2048) ALLOWED_FORMATS = ['summary', 'detailed'] @staticmethod def validate_inputs( query: str, constraints: str, images: List[str], top_k: int, report_format: str ) -> Tuple[bool, str]: """ Validate all user inputs Args: query: User's query string constraints: User's constraints string images: List of image paths top_k: Number of top results to return report_format: Type of report to generate Returns: Tuple(is_valid: bool, error_message: str) """ try: # Query validation if not query or query.isspace(): return False, "Query is required" if len(query) > InputValidator.MAX_QUERY_LENGTH: return False, f"Query too long (max {InputValidator.MAX_QUERY_LENGTH} characters)" # Images validation if not images: return False, "At least one image is required" if len(images) > InputValidator.MAX_IMAGES: return False, f"Too many images. Maximum allowed: {InputValidator.MAX_IMAGES}" # Process each image for img_path in images: # File type check file_ext = os.path.splitext(img_path)[1].lower() if file_ext not in InputValidator.ALLOWED_IMAGE_TYPES: return False, f"Invalid image type: {file_ext}. Allowed types: {', '.join(InputValidator.ALLOWED_IMAGE_TYPES)}" # File size check file_size_mb = os.path.getsize(img_path) / (1024 * 1024) if file_size_mb > InputValidator.MAX_IMAGE_SIZE_MB: return False, f"Image too large: {file_size_mb:.1f}MB. Maximum size: {InputValidator.MAX_IMAGE_SIZE_MB}MB" # Image integrity and resolution check try: with Image.open(img_path) as img: img.verify() # Verify image integrity width, height = img.size if width > InputValidator.MAX_IMAGE_RESOLUTION[0] or height > InputValidator.MAX_IMAGE_RESOLUTION[1]: return False, f"Image resolution too high. Maximum: {InputValidator.MAX_IMAGE_RESOLUTION[0]}x{InputValidator.MAX_IMAGE_RESOLUTION[1]}" except Exception as e: return False, f"Invalid or corrupted image: {os.path.basename(img_path)}" # Top-k validation if not isinstance(top_k, int) or top_k < 1: return False, "Top-k must be a positive integer" if top_k > len(images): return False, f"Top-k ({top_k}) cannot be larger than number of images ({len(images)})" # Report format validation if report_format not in InputValidator.ALLOWED_FORMATS: return False, f"Invalid report format. Allowed formats: {', '.join(InputValidator.ALLOWED_FORMATS)}" # Optional constraints validation if constraints and len(constraints) > InputValidator.MAX_QUERY_LENGTH: return False, f"Constraints too long (max {InputValidator.MAX_QUERY_LENGTH} characters)" return True, "" except Exception as e: return False, f"Validation error: {str(e)}" validator = InputValidator() validate_inputs = validator.validate_inputs