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("""

๐ŸŽฏ Advanced AI Size Finder

Intelligent sizing with 3D body modeling, fabric analysis & style recommendations

๐Ÿš€ No AI model needed! Pure calculation engine with dynamic brand support

""") with gr.Tab("๐ŸŽฏ Find My Size"): # Step 1: Basic Info gr.HTML("""

Step 1: Tell us about yourself

""") with gr.Row(): with gr.Column(scale=1): gender = gr.Textbox( label="I am shopping for", placeholder="e.g., Male, Female, Unisex", value="Unisex", elem_classes=["highlight"], info="Enter gender - we'll handle it automatically" ) with gr.Column(scale=1): body_type = gr.Textbox( label="My body type is", placeholder="e.g., Slim, Regular, Athletic, Curvy, Plus-size", value="Regular", elem_classes=["highlight"], info="Enter your body type - we'll handle it automatically" ) # Step 2: Measurements gr.HTML("""

Step 2: Your measurements (just 2 required!)

Enter with any unit: inches, cm, feet - we understand them all! ๐Ÿ“

""") with gr.Row(): with gr.Column(scale=1): gr.Markdown("#### ๐ŸŽฏ **Required Measurements**") chest_input = gr.Textbox( label="Chest/Bust", placeholder="e.g., 40 inches, 102 cm", elem_classes=["highlight"] ) waist_input = gr.Textbox( label="Waist", placeholder="e.g., 34 inches, 86 cm", elem_classes=["highlight"] ) with gr.Column(scale=1): gr.Markdown("#### ๐Ÿ“ **Optional (for better accuracy)**") height_input = gr.Textbox(label="Height", placeholder="e.g., 5.8 feet, 175 cm") weight_input = gr.Textbox(label="Weight", placeholder="e.g., 70 kg, 154 lbs") # Additional measurements in expandable section with gr.Accordion("โž• More measurements (optional)", open=False): with gr.Row(): with gr.Column(): shoulder_width_input = gr.Textbox(label="Shoulder Width", placeholder="e.g., 18 inches") sleeve_length_input = gr.Textbox(label="Sleeve Length", placeholder="e.g., 25 inches") neck_circumference_input = gr.Textbox(label="Neck Circumference", placeholder="e.g., 16 inches") with gr.Column(): shirt_length_input = gr.Textbox(label="Preferred Shirt Length", placeholder="e.g., 28 inches") armhole_size_input = gr.Textbox(label="Armhole Size", placeholder="e.g., 9 inches") inseam_input = gr.Textbox(label="Inseam", placeholder="e.g., 32 inches") thigh_circumference_input = gr.Textbox(label="Thigh Circumference", placeholder="e.g., 24 inches") # Step 3: Garment Info gr.HTML("""

Step 3: What are you buying?

""") with gr.Row(): with gr.Column(): product_name = gr.Textbox( label="Product Name", placeholder="e.g., Cotton Oxford Shirt", elem_classes=["highlight"] ) brand = gr.Textbox( label="Brand", placeholder="e.g., Zara, Nike, Your Brand Name", value="Other", elem_classes=["highlight"], info="Enter any brand name - we'll handle the sizing automatically" ) with gr.Column(): category = gr.Textbox( label="Category", placeholder="e.g., T-Shirt, Casual Shirt, Dress, etc.", value="Casual Shirt", elem_classes=["highlight"], info="Enter any clothing category - we'll handle it automatically" ) available_sizes_str = gr.Textbox( label="Available Sizes", placeholder="XS, S, M, L, XL, XXL", value="S, M, L, XL", elem_classes=["highlight"] ) # Step 4: Advanced Options gr.HTML("""

Step 4: Advanced Intelligence Options

Fine-tune your recommendation with fabric, season, and activity preferences

""") with gr.Row(): with gr.Column(): fabric_type = gr.Textbox( label="Fabric Type", placeholder="e.g., RIGID, LOW_STRETCH, MEDIUM_STRETCH, HIGH_STRETCH, KNIT", value="MEDIUM_STRETCH", info="How much does the fabric stretch?" ) season = gr.Textbox( label="Season", placeholder="e.g., SUMMER, SPRING_FALL, WINTER, ALL_SEASON", value="ALL_SEASON", info="When will you wear this?" ) with gr.Column(): activity = gr.Textbox( label="Activity Type", placeholder="e.g., ATHLETIC, OFFICE, CASUAL, FORMAL, LOUNGEWEAR", value="CASUAL", info="What will you be doing?" ) occasion = gr.Textbox( label="Occasion", placeholder="e.g., BUSINESS_MEETING, WEDDING, DATE_NIGHT, WEEKEND_CASUAL, WORKOUT, BEACH", value="WEEKEND_CASUAL", info="Where will you wear this?" ) # Step 5: Size Chart with gr.Accordion("๐Ÿ“Š Size Chart (expand to add garment measurements)", open=True): gr.Markdown("*Copy the brand's size chart here. Click 'Load Example' to see the format.*") with gr.Row(): size_measurements_json = gr.Code( language="json", label="Paste size chart measurements here", value=load_example_measurements(), lines=8 ) with gr.Column(scale=1): load_example_btn = gr.Button("๐Ÿ“ Load Example", variant="secondary", size="sm") load_example_btn.click( fn=load_example_measurements, outputs=size_measurements_json ) gr.Markdown(""" ๐Ÿ’ก Tip: Include chest, waist, hip, shoulder, and length """) # Get Recommendation Button gr.HTML("
") predict_btn = gr.Button( "๐ŸŽฏ Get Advanced Size Recommendation", variant="primary", elem_classes=["big-button"] ) # Results Section with gr.Row(): output = gr.Markdown( label="Your Size Recommendation", value="", elem_classes=["result-box"] ) with gr.Tab("๐Ÿ’ก Examples"): gr.HTML("""

Try these examples to see advanced features!

""") def load_athletic_example(): return [ "Male", "Athletic", "42 inches", "32 inches", "5.11 feet", "180 lbs", "18 inches", "", "", "", "", "", "", "Performance T-Shirt", "Nike", "T-Shirt", "S, M, L, XL", load_example_measurements(), "HIGH_STRETCH", "SUMMER", "ATHLETIC", "WORKOUT" ] def load_formal_example(): return [ "Female", "Regular", "36 inches", "30 inches", "5.6 feet", "140 lbs", "", "", "", "", "", "", "", "Cocktail Dress", "Nordstrom", "Dress", "XS, S, M, L", '{"XS": {"chest": 32, "waist": 26, "hip": 34, "length": 35}, "S": {"chest": 34, "waist": 28, "hip": 36, "length": 36}, "M": {"chest": 36, "waist": 30, "hip": 38, "length": 37}, "L": {"chest": 38, "waist": 32, "hip": 40, "length": 38}}', "LOW_STRETCH", "SPRING_FALL", "FORMAL", "WEDDING" ] with gr.Row(): athletic_btn = gr.Button("๐Ÿƒ Athletic Wear Example", variant="primary", size="lg") formal_btn = gr.Button("๐Ÿ‘— Formal Wear Example", variant="primary", size="lg") athletic_btn.click( fn=load_athletic_example, outputs=[ gender, body_type, chest_input, waist_input, height_input, weight_input, shoulder_width_input, sleeve_length_input, neck_circumference_input, shirt_length_input, armhole_size_input, inseam_input, thigh_circumference_input, product_name, brand, category, available_sizes_str, size_measurements_json, fabric_type, season, activity, occasion ] ) formal_btn.click( fn=load_formal_example, outputs=[ gender, body_type, chest_input, waist_input, height_input, weight_input, shoulder_width_input, sleeve_length_input, neck_circumference_input, shirt_length_input, armhole_size_input, inseam_input, thigh_circumference_input, product_name, brand, category, available_sizes_str, size_measurements_json, fabric_type, season, activity, occasion ] ) with gr.Tab("๐Ÿท๏ธ Brand Management"): gr.HTML("""

Add Custom Brand Sizing Data

Dynamically add new brands with their specific sizing characteristics

""") with gr.Row(): with gr.Column(): new_brand_name = gr.Textbox( label="Brand Name", placeholder="e.g., My Custom Brand", elem_classes=["highlight"] ) brand_fit_type = gr.Textbox( label="Fit Type", placeholder="e.g., standard, runs_small, runs_large, asian_sizing, athletic, european, junior_sizing, classic", value="standard", info="How does this brand typically fit?" ) brand_adjustment = gr.Slider( minimum=-3.0, maximum=3.0, step=0.5, value=0.0, label="Size Adjustment", info="Positive = runs large, Negative = runs small" ) add_brand_btn = gr.Button("โž• Add Brand", variant="primary") with gr.Column(): gr.Markdown("### Current Brands") current_brands = gr.Textbox( label="Available Brands", value=", ".join(recommender.get_available_brands()), interactive=False, lines=10 ) def add_new_brand(brand_name, fit_type, adjustment): if not brand_name.strip(): return "Please enter a brand name", ", ".join(recommender.get_available_brands()) result = recommender.add_brand_data(brand_name, fit_type, adjustment) return result, ", ".join(recommender.get_available_brands()) add_brand_btn.click( fn=add_new_brand, inputs=[new_brand_name, brand_fit_type, brand_adjustment], outputs=[gr.Textbox(label="Result"), current_brands] ) with gr.Tab("โ„น๏ธ How It Works"): gr.HTML("""

๐Ÿง  Advanced AI Without the AI Model!

๐ŸŽฏ Pure Calculation Engine

No 20B parameter model needed! We use advanced algorithms that run instantly and cost $0.

๐Ÿ“ 3D Body Volume Modeling

We calculate your body's 3D shape, not just flat measurements, for superior fit prediction.

๐Ÿงต Fabric Intelligence

Different fabrics fit differently. We adjust recommendations based on stretch and structure.

๐ŸŒก๏ธ Seasonal & Activity Optimization

Winter clothes need room for layers. Athletic wear needs flexibility. We factor it all in.

๐Ÿท๏ธ Dynamic Brand-Specific Sizing

We know Zara runs small and H&M runs large. Plus, you can add any new brand with custom sizing data!

๐Ÿ‘” Fashion Advisor

Get style recommendations, coordinated sizing, and occasion-specific advice.

โœจ Result: Instant, accurate sizing with $0 infrastructure cost!

""") # Connect the main prediction function predict_btn.click( fn=predict_size, inputs=[ 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, product_name, brand, category, available_sizes_str, size_measurements_json, fabric_type, season, activity, occasion ], outputs=output ) if __name__ == "__main__": demo.launch()