from typing import Dict, Optional import numpy as np class MeasurementProcessor: NORMALIZATION_FACTORS = { "height": 200.0, "weight": 100.0, "chest": 150.0, "waist": 150.0, "hips": 150.0, "shoulder_width": 60.0, "arm_length": 80.0, "leg_length": 120.0, "inseam": 100.0, } REQUIRED_MEASUREMENTS = [ "height", "weight", "chest", "waist", "hips", ] OPTIONAL_MEASUREMENTS = { "shoulder_width": 40.0, "arm_length": 60.0, "leg_length": 90.0, "inseam": 75.0, } @classmethod def validate_measurements(cls, measurements: Dict) -> Dict[str, str]: errors = [] for field in cls.REQUIRED_MEASUREMENTS: if field not in measurements: errors.append(f"Missing required measurement: {field}") elif not isinstance(measurements[field], (int, float)): errors.append(f"Invalid type for {field}: must be number") elif measurements[field] <= 0: errors.append(f"Invalid value for {field}: must be positive") for field, default in cls.OPTIONAL_MEASUREMENTS.items(): if field in measurements: if not isinstance(measurements[field], (int, float)): errors.append(f"Invalid type for {field}: must be number") elif measurements[field] <= 0: errors.append(f"Invalid value for {field}: must be positive") return { "valid": len(errors) == 0, "errors": errors } @classmethod def normalize_measurements(cls, measurements: Dict) -> np.ndarray: processed = measurements.copy() for field, default in cls.OPTIONAL_MEASUREMENTS.items(): if field not in processed: processed[field] = default normalized = [] measurement_order = [ "height", "weight", "chest", "waist", "hips", "shoulder_width", "arm_length", "leg_length", "inseam" ] for field in measurement_order: value = processed[field] factor = cls.NORMALIZATION_FACTORS[field] normalized.append(value / factor) return np.array(normalized, dtype=np.float32) @classmethod def process(cls, measurements: Dict) -> np.ndarray: validation = cls.validate_measurements(measurements) if not validation["valid"]: raise ValueError(f"Invalid measurements: {', '.join(validation['errors'])}") return cls.normalize_measurements(measurements) def process_measurements(measurements: Dict) -> np.ndarray: return MeasurementProcessor.process(measurements)