import gradio as gr import json from typing import Dict, Any, Optional, Tuple, List import re import os import numpy as np from datetime import datetime import pickle from dataclasses import dataclass from enum import Enum class FabricType(Enum): """Fabric stretch and structure properties""" RIGID = "rigid" # Denim, canvas, leather LOW_STRETCH = "low_stretch" # Cotton, linen MEDIUM_STRETCH = "medium_stretch" # Cotton blend, jersey HIGH_STRETCH = "high_stretch" # Spandex blend, athletic wear KNIT = "knit" # Sweaters, knitwear class SeasonType(Enum): """Seasonal clothing categories""" SUMMER = "summer" SPRING_FALL = "spring_fall" WINTER = "winter" ALL_SEASON = "all_season" class ActivityType(Enum): """Activity-based fit requirements""" ATHLETIC = "athletic" # Needs movement flexibility OFFICE = "office" # Professional, structured CASUAL = "casual" # Everyday comfort FORMAL = "formal" # Events, fitted LOUNGEWEAR = "loungewear" # Maximum comfort class OccasionType(Enum): """Occasion-based fit preferences""" BUSINESS_MEETING = "business_meeting" WEDDING = "wedding" DATE_NIGHT = "date_night" WEEKEND_CASUAL = "weekend_casual" WORKOUT = "workout" BEACH = "beach" @dataclass class FitProfile: """User's fit preferences and history""" user_id: str preferred_fit: str # "slim", "regular", "relaxed" size_history: List[Dict] # Previous purchases return_history: List[Dict] # Returns with reasons body_changes: List[Dict] # Weight/measurement changes over time climate: str # "hot", "cold", "moderate", "variable" class AdvancedSizeRecommender: def __init__(self): # Initialize data storage self.user_profiles = {} self.brand_fit_data = self.load_brand_data() self.historical_data = [] # Advanced body ratio tables with 3D considerations self.body_ratios = { 'male': { 'chest_to_waist': 1.2, 'shoulder_to_chest': 0.45, 'neck_to_chest': 0.4, 'sleeve_chest_ratio': 0.625, 'shirt_length_chest': 0.75, 'armhole_chest_ratio': 0.25, 'thigh_waist_ratio': 1.4, 'inseam_height_ratio': 0.45, # 3D volume ratios 'chest_depth_ratio': 0.35, # Front to back 'waist_depth_ratio': 0.32, 'hip_to_waist': 1.05, 'bicep_chest_ratio': 0.38, 'forearm_bicep_ratio': 0.83 }, 'female': { 'chest_to_waist': 1.25, 'shoulder_to_chest': 0.42, 'neck_to_chest': 0.38, 'sleeve_chest_ratio': 0.6, 'shirt_length_chest': 0.7, 'armhole_chest_ratio': 0.24, 'thigh_waist_ratio': 1.5, 'inseam_height_ratio': 0.43, # 3D volume ratios 'chest_depth_ratio': 0.38, 'waist_depth_ratio': 0.30, 'hip_to_waist': 1.35, 'bicep_chest_ratio': 0.32, 'forearm_bicep_ratio': 0.80 } } # Fabric stretch factors self.fabric_stretch_factors = { FabricType.RIGID: 0.0, FabricType.LOW_STRETCH: 0.02, FabricType.MEDIUM_STRETCH: 0.05, FabricType.HIGH_STRETCH: 0.10, FabricType.KNIT: 0.08 } # Seasonal adjustment factors self.seasonal_adjustments = { SeasonType.SUMMER: -0.5, # Tighter fit for hot weather SeasonType.SPRING_FALL: 0.0, # Standard fit SeasonType.WINTER: 1.5, # Room for layers SeasonType.ALL_SEASON: 0.5 # Slight room } # Activity-based fit adjustments (inches) self.activity_adjustments = { ActivityType.ATHLETIC: { 'chest': 2.0, 'waist': 1.5, 'armhole': 1.0, 'thigh': 2.0 }, ActivityType.OFFICE: { 'chest': 1.0, 'waist': 0.5, 'armhole': 0.5, 'thigh': 1.0 }, ActivityType.CASUAL: { 'chest': 1.5, 'waist': 1.0, 'armhole': 0.75, 'thigh': 1.5 }, ActivityType.FORMAL: { 'chest': 0.5, 'waist': 0.25, 'armhole': 0.25, 'thigh': 0.5 }, ActivityType.LOUNGEWEAR: { 'chest': 3.0, 'waist': 2.5, 'armhole': 1.5, 'thigh': 3.0 } } # Unit conversion factors self.length_conversions = { 'inches': 1.0, 'in': 1.0, '"': 1.0, 'centimeters': 0.393701, 'cm': 0.393701, 'meters': 39.3701, 'm': 39.3701, 'feet': 12.0, 'ft': 12.0, "'": 12.0, 'millimeters': 0.0393701, 'mm': 0.0393701 } self.weight_conversions = { 'pounds': 1.0, 'lbs': 1.0, 'lb': 1.0, 'kilograms': 2.20462, 'kg': 2.20462, 'grams': 0.00220462, 'g': 0.00220462, 'stones': 14.0, 'st': 14.0 } def load_brand_data(self) -> Dict: """Load brand-specific sizing data""" return { "Zara": {"fit": "runs_small", "adjustment": -1.0}, "H&M": {"fit": "runs_large", "adjustment": 1.0}, "Nike": {"fit": "athletic", "adjustment": 0.5}, "Uniqlo": {"fit": "asian_sizing", "adjustment": -1.5}, "Gap": {"fit": "true_to_size", "adjustment": 0.0}, "Levi's": {"fit": "true_to_size", "adjustment": 0.0}, "Adidas": {"fit": "european", "adjustment": 0.5}, "Ralph Lauren": {"fit": "classic", "adjustment": 0.5}, "Forever 21": {"fit": "junior_sizing", "adjustment": -1.0}, "Nordstrom": {"fit": "true_to_size", "adjustment": 0.0}, "Other": {"fit": "standard", "adjustment": 0.0} } def parse_measurement(self, value: str, measurement_type: str = 'length') -> float: """Parse measurement string with units and convert to standard units""" if not value or value == "0" or value == 0: return 0.0 value_str = str(value).lower().strip() # Extract number and unit match = re.match(r'([0-9]*\.?[0-9]+)\s*([a-zA-Z"\']*)', value_str) if not match: try: return float(value_str) except: return 0.0 number = float(match.group(1)) unit = match.group(2).strip() # Choose conversion table conversions = self.length_conversions if measurement_type == 'length' else self.weight_conversions # Find matching unit conversion_factor = 1.0 for unit_key, factor in conversions.items(): if unit == unit_key or unit in unit_key: conversion_factor = factor break return number * conversion_factor def calculate_3d_body_volume(self, measurements: Dict, gender: str) -> Dict: """Calculate 3D body volume estimates for better fit analysis""" ratios = self.body_ratios.get(gender.lower(), self.body_ratios['male']) chest = measurements.get('chest', 0) waist = measurements.get('waist', 0) hip = measurements.get('hip', waist * ratios['hip_to_waist']) # Estimate body volumes (simplified cylindrical approximations) chest_volume = { 'circumference': chest, 'depth': chest * ratios['chest_depth_ratio'], 'volume_factor': np.pi * (chest / (2 * np.pi)) ** 2 } waist_volume = { 'circumference': waist, 'depth': waist * ratios['waist_depth_ratio'], 'volume_factor': np.pi * (waist / (2 * np.pi)) ** 2 } # Arm volume for sleeve fit bicep = chest * ratios['bicep_chest_ratio'] forearm = bicep * ratios['forearm_bicep_ratio'] arm_volume = { 'bicep': bicep, 'forearm': forearm, 'average': (bicep + forearm) / 2 } return { 'chest_volume': chest_volume, 'waist_volume': waist_volume, 'arm_volume': arm_volume, 'hip': hip } def apply_fabric_intelligence(self, base_size: str, fabric_type: FabricType, measurements: Dict, garment_measurements: Dict) -> Tuple[str, str]: """Adjust size recommendation based on fabric properties""" stretch_factor = self.fabric_stretch_factors[fabric_type] # Calculate how much the fabric will stretch chest_stretch = garment_measurements.get('chest', 0) * stretch_factor waist_stretch = garment_measurements.get('waist', 0) * stretch_factor # For stretchy fabrics, we can go down a size if measurements are borderline if stretch_factor >= 0.05: # Medium to high stretch size_order = ["XS", "S", "M", "L", "XL", "XXL", "XXXL"] current_idx = size_order.index(base_size) if base_size in size_order else 2 # Check if user's measurements would fit with stretch chest_diff = measurements.get('chest', 0) - (garment_measurements.get('chest', 0) + chest_stretch) waist_diff = measurements.get('waist', 0) - (garment_measurements.get('waist', 0) + waist_stretch) if chest_diff < 1 and waist_diff < 1 and current_idx > 0: explanation = f"With {fabric_type.value} fabric's stretch properties, you can comfortably wear a size down" return size_order[current_idx - 1], explanation elif stretch_factor == 0: # Rigid fabric # For rigid fabrics, ensure there's enough room if measurements.get('chest', 0) - garment_measurements.get('chest', 0) < 1: size_order = ["XS", "S", "M", "L", "XL", "XXL", "XXXL"] current_idx = size_order.index(base_size) if base_size in size_order else 2 if current_idx < len(size_order) - 1: explanation = f"Rigid {fabric_type.value} fabric requires more room for comfort" return size_order[current_idx + 1], explanation return base_size, f"Standard fit for {fabric_type.value} fabric" def apply_seasonal_adjustments(self, measurements: Dict, season: SeasonType) -> Dict: """Adjust measurements based on seasonal requirements""" adjustment = self.seasonal_adjustments[season] adjusted = measurements.copy() # Add room for layering in winter, reduce for summer for key in ['chest', 'waist', 'armhole']: if key in adjusted and adjusted[key] > 0: adjusted[key] += adjustment return adjusted def apply_activity_adjustments(self, measurements: Dict, activity: ActivityType) -> Dict: """Adjust measurements based on activity requirements""" adjustments = self.activity_adjustments[activity] adjusted = measurements.copy() for key, adjustment in adjustments.items(): if key in adjusted and adjusted[key] > 0: adjusted[key] += adjustment return adjusted def estimate_missing_measurements(self, measurements: Dict, gender: str = 'unisex') -> Dict: """Estimate missing body measurements using anthropometric ratios""" estimated = measurements.copy() # Determine gender ratios if gender.lower() in ['male', 'female']: ratios = self.body_ratios[gender.lower()] else: # Use average ratios for unisex male_ratios = self.body_ratios['male'] female_ratios = self.body_ratios['female'] ratios = {k: (male_ratios[k] + female_ratios[k]) / 2 for k in male_ratios} chest = estimated.get('chest', 0) waist = estimated.get('waist', 0) weight = estimated.get('weight', 0) # Estimate chest from waist if chest == 0 and waist > 0: estimated['chest'] = waist * ratios['chest_to_waist'] chest = estimated['chest'] # Estimate waist from chest if waist == 0 and chest > 0: estimated['waist'] = chest / ratios['chest_to_waist'] waist = estimated['waist'] # Estimate other measurements from chest if chest > 0: if estimated.get('shoulder_width', 0) == 0: estimated['shoulder_width'] = chest * ratios['shoulder_to_chest'] if estimated.get('neck_circumference', 0) == 0: estimated['neck_circumference'] = chest * ratios['neck_to_chest'] if estimated.get('sleeve_length', 0) == 0: estimated['sleeve_length'] = chest * ratios['sleeve_chest_ratio'] if estimated.get('shirt_length', 0) == 0: estimated['shirt_length'] = chest * ratios['shirt_length_chest'] if estimated.get('armhole_size', 0) == 0: estimated['armhole_size'] = chest * ratios['armhole_chest_ratio'] # Estimate hip from waist if waist > 0: estimated['hip'] = waist * ratios['hip_to_waist'] if estimated.get('thigh_circumference', 0) == 0: estimated['thigh_circumference'] = waist * ratios['thigh_waist_ratio'] # Estimate height from weight (rough approximation) if weight > 0 and estimated.get('height', 0) == 0: # BMI-based height estimation (assuming average BMI of 22-25) estimated['height'] = ((weight / 23) ** 0.5) * 39.37 # Convert to inches # Estimate inseam from height if estimated.get('height', 0) > 0 and estimated.get('inseam', 0) == 0: estimated['inseam'] = estimated['height'] * ratios['inseam_height_ratio'] return estimated def calculate_best_size(self, user_measurements: Dict, garment_data: Dict, fabric_type: FabricType = FabricType.MEDIUM_STRETCH, season: SeasonType = SeasonType.ALL_SEASON, activity: ActivityType = ActivityType.CASUAL) -> Tuple[str, str, int, Dict]: """Calculate the best matching size and overfit size with advanced factors""" # Apply adjustments based on context adjusted_measurements = user_measurements.copy() if season != SeasonType.ALL_SEASON: adjusted_measurements = self.apply_seasonal_adjustments(adjusted_measurements, season) if activity != ActivityType.CASUAL: adjusted_measurements = self.apply_activity_adjustments(adjusted_measurements, activity) # Get 3D volume calculations body_volumes = self.calculate_3d_body_volume(adjusted_measurements, garment_data.get('gender', 'unisex')) available_sizes = garment_data.get('available_sizes', []) # Sort sizes from smallest to largest for better logic size_order = ["XS", "S", "M", "L", "XL", "XXL", "XXXL"] sorted_sizes = sorted(available_sizes, key=lambda x: size_order.index(x) if x in size_order else 999) best_fit_size = "M" overfit_size = "L" best_score = float('inf') detailed_analysis = {} # Find sizes that actually have measurements valid_sizes = [] for size in sorted_sizes: size_measurements = garment_data.get(f'{size.lower()}_measurements', {}) if size_measurements and size_measurements.get('chest', 0) > 0: valid_sizes.append((size, size_measurements)) if not valid_sizes: return "M", "L", 50, {"error": "No valid size measurements found"} # Calculate fit scores for each valid size size_scores = [] print(f"DEBUG: Calculating scores for {len(valid_sizes)} valid sizes") print(f"DEBUG: User measurements: {adjusted_measurements}") for size, size_measurements in valid_sizes: # Calculate differences with 3D considerations chest_diff = abs(adjusted_measurements.get('chest', 0) - size_measurements.get('chest', 0)) waist_diff = abs(adjusted_measurements.get('waist', 0) - size_measurements.get('waist', 0)) hip_diff = abs(body_volumes['hip'] - size_measurements.get('hip', body_volumes['hip'])) shoulder_diff = abs(adjusted_measurements.get('shoulder_width', 0) - size_measurements.get('shoulder', 0)) # Consider fabric stretch stretch_factor = self.fabric_stretch_factors[fabric_type] if stretch_factor > 0: chest_diff *= (1 - stretch_factor) waist_diff *= (1 - stretch_factor) # Weighted score with 3D volume considerations score = (chest_diff * 2.5) + (waist_diff * 2.0) + (hip_diff * 1.5) + (shoulder_diff * 1.0) # Brand-specific adjustments brand = garment_data.get('brand', '') if brand in self.brand_fit_data: brand_adjustment = self.brand_fit_data[brand]['adjustment'] score -= brand_adjustment # Negative adjustment means brand runs small print(f"DEBUG: Size {size} - Chest diff: {chest_diff:.2f}, Waist diff: {waist_diff:.2f}, Score: {score:.2f}") size_scores.append((size, score, size_measurements)) # Sort by score to find best fit size_scores.sort(key=lambda x: x[1]) print(f"DEBUG: Sorted scores: {[(s[0], s[1]) for s in size_scores]}") if size_scores: best_fit_size, best_score, best_measurements = size_scores[0] print(f"DEBUG: Best fit: {best_fit_size} with score {best_score:.2f}") # Find overfit size (one size larger than best fit) size_idx = size_order.index(best_fit_size) if best_fit_size in size_order else 2 if size_idx < len(size_order) - 1: overfit_size = size_order[size_idx + 1] # Make sure overfit size is available if overfit_size not in [s[0] for s in size_scores]: # Find the next available larger size for i in range(size_idx + 1, len(size_order)): if size_order[i] in [s[0] for s in size_scores]: overfit_size = size_order[i] break else: overfit_size = best_fit_size # Already largest size # Create detailed analysis for best fit detailed_analysis = { 'best_fit_size': best_fit_size, 'overfit_size': overfit_size, 'chest_fit': self.assess_fit(adjusted_measurements.get('chest', 0), best_measurements.get('chest', 0)), 'waist_fit': self.assess_fit(adjusted_measurements.get('waist', 0), best_measurements.get('waist', 0)), 'hip_fit': self.assess_fit(body_volumes['hip'], best_measurements.get('hip', body_volumes['hip'])), 'shoulder_fit': self.assess_fit(adjusted_measurements.get('shoulder_width', 0), best_measurements.get('shoulder', 0)), 'length_appropriate': self.assess_length(adjusted_measurements.get('height', 0), best_measurements.get('length', 0)), 'volume_analysis': body_volumes, 'fabric_consideration': f"{fabric_type.value} - {stretch_factor*100:.0f}% stretch", 'seasonal_adjustment': f"{season.value} - {self.seasonal_adjustments[season]:+.1f} inches", 'activity_suitability': f"{activity.value} fit requirements applied", 'fit_reasoning': self.get_fit_reasoning(adjusted_measurements, best_measurements, best_fit_size, overfit_size) } # Calculate confidence based on fit quality confidence = max(50, min(95, 100 - int(best_score * 2))) # Apply fabric-based size adjustment if needed final_best_size, fabric_note = self.apply_fabric_intelligence(best_fit_size, fabric_type, adjusted_measurements, garment_data.get(f'{best_fit_size.lower()}_measurements', {})) final_overfit_size, _ = self.apply_fabric_intelligence(overfit_size, fabric_type, adjusted_measurements, garment_data.get(f'{overfit_size.lower()}_measurements', {})) detailed_analysis['fabric_adjustment'] = fabric_note return final_best_size, final_overfit_size, confidence, detailed_analysis def get_fit_reasoning(self, user_measurements: Dict, garment_measurements: Dict, best_size: str, overfit_size: str) -> str: """Provide reasoning for size recommendations""" chest = user_measurements.get('chest', 0) waist = user_measurements.get('waist', 0) garment_chest = garment_measurements.get('chest', 0) garment_waist = garment_measurements.get('waist', 0) reasoning = [] if chest > 0 and garment_chest > 0: chest_diff = garment_chest - chest if abs(chest_diff) <= 1: reasoning.append(f"Perfect chest fit ({chest_diff:+.1f}\")") elif chest_diff > 1: reasoning.append(f"Comfortable chest room (+{chest_diff:.1f}\")") else: reasoning.append(f"Snug chest fit ({chest_diff:+.1f}\")") if waist > 0 and garment_waist > 0: waist_diff = garment_waist - waist if abs(waist_diff) <= 1: reasoning.append(f"Perfect waist fit ({waist_diff:+.1f}\")") elif waist_diff > 1: reasoning.append(f"Comfortable waist room (+{waist_diff:.1f}\")") else: reasoning.append(f"Snug waist fit ({waist_diff:+.1f}\")") if best_size != overfit_size: reasoning.append(f"Oversized option: {overfit_size} for relaxed style") return " | ".join(reasoning) if reasoning else "Standard fit analysis" def assess_fit(self, user_measurement: float, garment_measurement: float) -> str: """Assess how well a measurement fits""" diff = garment_measurement - user_measurement if abs(diff) <= 0.5: return "Perfect" elif 0.5 < diff <= 2: return "Good (comfortable)" elif -1 <= diff < -0.5: return "Snug (fitted)" elif 2 < diff <= 4: return "Relaxed" elif diff > 4: return "Loose" else: return "Too tight" def assess_length(self, height: float, garment_length: float) -> str: """Assess if garment length is appropriate for height""" if height == 0 or garment_length == 0: return "Unable to assess" # General rule: shirt length should be about 40% of height for tucked, 42% for untucked ideal_length = height * 0.41 diff = abs(garment_length - ideal_length) if diff <= 1: return "Perfect length" elif diff <= 2: return "Good length" elif garment_length < ideal_length - 2: return "May be short" else: return "May be long" def get_style_recommendations(self, measurements: Dict, body_type: str, occasion: OccasionType = OccasionType.WEEKEND_CASUAL) -> Dict: """Provide AI fashion advisor recommendations""" recommendations = { 'fit_style': '', 'coordinated_sizing': {}, 'occasion_tips': '', 'climate_advice': '' } # Determine ideal fit style based on body type if body_type.lower() == 'athletic': recommendations['fit_style'] = "Try slim fit shirts to accentuate your athletic build. Ensure enough room in chest and shoulders." elif body_type.lower() == 'slim': recommendations['fit_style'] = "Slim or tailored fit works best. Avoid overly loose clothing that can make you appear smaller." elif body_type.lower() == 'regular': recommendations['fit_style'] = "Classic or regular fit provides the best balance. You have flexibility with most styles." elif body_type.lower() == 'curvy': recommendations['fit_style'] = "Look for items with stretch fabric and proper waist definition. Avoid boxy cuts." elif body_type.lower() == 'plus-size': recommendations['fit_style'] = "Opt for structured fabrics with a comfortable fit. Proper shoulder and chest fit is crucial." # Coordinated sizing advice chest = measurements.get('chest', 0) if chest > 0: # Jacket should be 4-6 inches larger than chest for layering recommendations['coordinated_sizing'] = { 'jacket': f"If chest is {chest:.0f}\", look for jackets with {chest+5:.0f}\"-{chest+6:.0f}\" chest", 'pants': "Match waist measurement, ensure proper rise for comfort", 'layering': "Base layer: true to size, Mid layer: +2 inches, Outer layer: +4-6 inches" } # Occasion-specific advice occasion_advice = { OccasionType.BUSINESS_MEETING: "Opt for a tailored fit with minimal ease. Ensure shoulders sit perfectly and length covers belt.", OccasionType.WEDDING: "Choose a slim or tailored fit. Ensure comfortable movement for dancing. Consider fabric breathability.", OccasionType.DATE_NIGHT: "Go for a fitted silhouette that flatters. Not too tight, but shows your shape well.", OccasionType.WEEKEND_CASUAL: "Relaxed fit works well. Prioritize comfort while maintaining a put-together look.", OccasionType.WORKOUT: "Choose performance fabrics with 4-way stretch. Size for full range of motion.", OccasionType.BEACH: "Looser fits work best for hot weather. Consider linen or lightweight cotton." } recommendations['occasion_tips'] = occasion_advice.get(occasion, "Choose based on comfort and activity level.") # Climate considerations recommendations['climate_advice'] = { 'hot': "Size down slightly for better air circulation. Choose moisture-wicking fabrics. Looser fits in lightweight materials.", 'cold': "Size up to accommodate layers. Ensure base layer fits close to body. Leave room for thermal wear.", 'humid': "Avoid tight fits that trap moisture. Natural fibers breathe better. Slightly loose is ideal.", 'variable': "Layer-friendly sizing is key. Base size should work with and without light layers." } return recommendations def save_user_profile(self, user_id: str, profile_data: Dict): """Save user profile and preferences""" self.user_profiles[user_id] = FitProfile( user_id=user_id, preferred_fit=profile_data.get('preferred_fit', 'regular'), size_history=profile_data.get('size_history', []), return_history=profile_data.get('return_history', []), body_changes=profile_data.get('body_changes', []), climate=profile_data.get('climate', 'moderate') ) def log_purchase_feedback(self, user_id: str, purchase_data: Dict): """Log purchase feedback to improve future recommendations""" if user_id in self.user_profiles: self.user_profiles[user_id].size_history.append({ 'date': datetime.now().isoformat(), 'brand': purchase_data.get('brand'), 'size': purchase_data.get('size'), 'fit_feedback': purchase_data.get('fit_feedback'), 'would_recommend': purchase_data.get('would_recommend', True) }) def get_brand_specific_recommendation(self, brand: str, base_size: str) -> Tuple[str, str]: """Adjust size based on brand-specific fitting""" # Normalize brand name (capitalize first letter) normalized_brand = brand.title() if brand else "Other" # Use brand data if available, otherwise use "Other" as default brand_info = self.brand_fit_data.get(normalized_brand, self.brand_fit_data["Other"]) size_order = ["XS", "S", "M", "L", "XL", "XXL", "XXXL"] if base_size not in size_order: return base_size, f"Standard sizing for {normalized_brand}" current_idx = size_order.index(base_size) if brand_info['fit'] == 'runs_small' and current_idx < len(size_order) - 1: return size_order[current_idx + 1], f"{normalized_brand} typically runs small - sized up" elif brand_info['fit'] == 'runs_large' and current_idx > 0: return size_order[current_idx - 1], f"{normalized_brand} typically runs large - sized down" elif brand_info['fit'] == 'asian_sizing' and current_idx < len(size_order) - 2: return size_order[current_idx + 2], f"{normalized_brand} uses Asian sizing - sized up significantly" return base_size, f"{normalized_brand} {brand_info['fit']} sizing applied" def add_brand_data(self, brand: str, fit_type: str = "standard", adjustment: float = 0.0): """Dynamically add new brand data""" normalized_brand = brand.title() if brand else "Other" self.brand_fit_data[normalized_brand] = { "fit": fit_type, "adjustment": adjustment } return f"Added {normalized_brand} with {fit_type} sizing" def get_available_brands(self) -> List[str]: """Get list of all available brands""" return list(self.brand_fit_data.keys()) # Initialize the recommender recommender = AdvancedSizeRecommender() def predict_size( # User measurements with units chest_input, shoulder_width_input, sleeve_length_input, neck_circumference_input, shirt_length_input, armhole_size_input, waist_input, inseam_input, thigh_circumference_input, weight_input, height_input, body_type, gender, # Garment info product_name, brand, category, available_sizes_str, # Size measurements size_measurements_json, # Advanced options fabric_type, season, activity, occasion ) -> str: """Enhanced prediction function with advanced intelligence""" try: # Parse all measurements with units user_data = { "chest": recommender.parse_measurement(chest_input, 'length'), "shoulder_width": recommender.parse_measurement(shoulder_width_input, 'length'), "sleeve_length": recommender.parse_measurement(sleeve_length_input, 'length'), "neck_circumference": recommender.parse_measurement(neck_circumference_input, 'length'), "shirt_length": recommender.parse_measurement(shirt_length_input, 'length'), "armhole_size": recommender.parse_measurement(armhole_size_input, 'length'), "waist": recommender.parse_measurement(waist_input, 'length'), "inseam": recommender.parse_measurement(inseam_input, 'length'), "thigh_circumference": recommender.parse_measurement(thigh_circumference_input, 'length'), "weight": recommender.parse_measurement(weight_input, 'weight'), "height": recommender.parse_measurement(height_input, 'length'), "body_type": body_type, "gender": gender } # Parse available sizes available_sizes = [size.strip().upper() for size in available_sizes_str.split(",") if size.strip()] # Parse size measurements JSON size_measurements = {} if size_measurements_json.strip(): try: size_measurements = json.loads(size_measurements_json) print(f"DEBUG: Parsed size measurements: {size_measurements}") except Exception as e: print(f"DEBUG: Error parsing size measurements: {e}") return "โ Error: Invalid size measurements format. Please use valid JSON." # Normalize inputs for better compatibility normalized_gender = gender.title() if gender else "Unisex" normalized_body_type = body_type.title() if body_type else "Regular" normalized_category = category.title() if category else "Casual Shirt" # Prepare garment data garment_data = { "product_name": product_name, "brand": brand, "category": normalized_category, "available_sizes": available_sizes, "gender": normalized_gender } # Add parsed size measurements for size, measurements in size_measurements.items(): garment_data[f"{size.lower()}_measurements"] = measurements print(f"DEBUG: Created garment_data: {garment_data}") # Validate that we have some measurements total_measurements = sum(1 for v in user_data.values() if isinstance(v, (int, float)) and v > 0) if total_measurements < 2: return "โ ๏ธ Please provide at least 2 body measurements for accurate recommendations." # Get estimated measurements estimated_measurements = recommender.estimate_missing_measurements(user_data, gender) # Convert string inputs to enums with fallback handling try: fabric_enum = FabricType[fabric_type.upper()] if fabric_type else FabricType.MEDIUM_STRETCH except KeyError: fabric_enum = FabricType.MEDIUM_STRETCH try: season_enum = SeasonType[season.upper()] if season else SeasonType.ALL_SEASON except KeyError: season_enum = SeasonType.ALL_SEASON try: activity_enum = ActivityType[activity.upper()] if activity else ActivityType.CASUAL except KeyError: activity_enum = ActivityType.CASUAL try: occasion_enum = OccasionType[occasion.upper()] if occasion else OccasionType.WEEKEND_CASUAL except KeyError: occasion_enum = OccasionType.WEEKEND_CASUAL # Get advanced size recommendation with both best fit and overfit best_size, overfit_size, confidence, analysis = recommender.calculate_best_size( estimated_measurements, garment_data, fabric_enum, season_enum, activity_enum ) # Apply brand-specific adjustments (handles any brand dynamically) final_best_size, brand_note = recommender.get_brand_specific_recommendation(brand, best_size) final_overfit_size, _ = recommender.get_brand_specific_recommendation(brand, overfit_size) # Get style recommendations style_advice = recommender.get_style_recommendations( estimated_measurements, normalized_body_type, occasion_enum ) # Format response with both recommendations if final_best_size == final_overfit_size: output = f"Size {final_best_size} will provide the best fit for your {normalized_body_type} body type, considering the {fabric_enum.value} fabric, {season_enum.value} season, and {activity_enum.value} use. {brand_note}" else: output = f"**Best Fit:** Size {final_best_size} | **Oversized Option:** Size {final_overfit_size} - If you like oversized clothes, use this size for your {normalized_body_type} body type, considering the {fabric_enum.value} fabric, {season_enum.value} season, and {activity_enum.value} use. {brand_note}" return output except Exception as e: return f"โ Processing Error: {str(e)}\nPlease check your inputs and try again." def load_example_measurements(): """Load example size measurements JSON""" example_sizes = { "XS": {"chest": 32, "waist": 26, "hip": 34, "shoulder": 14, "length": 25, "sleeve": 23}, "S": {"chest": 34, "waist": 28, "hip": 36, "shoulder": 15, "length": 26, "sleeve": 23.5}, "M": {"chest": 38, "waist": 32, "hip": 40, "shoulder": 16, "length": 27, "sleeve": 24}, "L": {"chest": 42, "waist": 36, "hip": 44, "shoulder": 17, "length": 28, "sleeve": 24.5}, "XL": {"chest": 46, "waist": 40, "hip": 48, "shoulder": 18, "length": 29, "sleeve": 25} } return json.dumps(example_sizes, indent=2) # Create Gradio interface with gr.Blocks(title="Advanced AI Size Finder", theme=gr.themes.Soft(), css=""" .container { max-width: 1200px; margin: auto; } .big-button { font-size: 20px !important; height: 60px !important; } .result-box { border: 2px solid #e0e0e0; border-radius: 10px; padding: 20px; margin-top: 20px; } .highlight { background-color: #f0f8ff; padding: 15px; border-radius: 8px; margin: 10px 0; } .advanced-options { background-color: #f9f9f9; padding: 20px; border-radius: 10px; margin-top: 20px; } """) as demo: gr.HTML("""
Intelligent sizing with 3D body modeling, fabric analysis & style recommendations
๐ No AI model needed! Pure calculation engine with dynamic brand support
Enter with any unit: inches, cm, feet - we understand them all! ๐
Dynamically add new brands with their specific sizing characteristics
No 20B parameter model needed! We use advanced algorithms that run instantly and cost $0.
We calculate your body's 3D shape, not just flat measurements, for superior fit prediction.
Different fabrics fit differently. We adjust recommendations based on stretch and structure.
Winter clothes need room for layers. Athletic wear needs flexibility. We factor it all in.
We know Zara runs small and H&M runs large. Plus, you can add any new brand with custom sizing data!
Get style recommendations, coordinated sizing, and occasion-specific advice.
โจ Result: Instant, accurate sizing with $0 infrastructure cost!