hackx / app.py
RohanVashisht's picture
Update app.py
39c7b18 verified
raw
history blame
30.4 kB
"""
Comprehensive Body Measurements Predictor with Brand Comparisons
Created by: RohanVashisht1234
Created on: 2025-02-22 21:26:00 UTC
This application provides:
1. Body measurements predictions based on height
2. Brand-specific size recommendations
"""
import gradio as gr
import pandas as pd
import numpy as np
from sklearn.preprocessing import LabelEncoder, StandardScaler
from sklearn.ensemble import RandomForestRegressor, RandomForestClassifier
from sklearn.metrics import r2_score, accuracy_score
import json
import logging
from datetime import datetime
# Constants
# Constants
CURRENT_TIME = "2025-02-22 21:39:09"
CURRENT_USER = "RohanVashisht1234"
CSV_PATH = 'bdm.csv'
SHIRT_SIZE_CHARTS_PATH = 'shirt_size_charts.json'
PANTS_SIZE_CHARTS_PATH = 'pants_size_charts.json'
# Set up logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
class ShirtPredictor:
def __init__(self):
self.models = {}
self.encoders = {}
self.scaler = StandardScaler()
self.categorical_columns = ['Size', 'Fit']
self.numerical_columns = [
'ChestWidth', 'ShoulderWidth', 'ArmLength',
'ShoulderToWaist', 'Belly', 'Waist'
]
self.accuracies = {}
self.units = {
'ChestWidth': 'cm',
'ShoulderWidth': 'cm',
'ArmLength': 'cm',
'ShoulderToWaist': 'cm',
'Belly': 'cm',
'Waist': 'cm',
'Weight': 'kg',
'TotalHeight': 'cm'
}
def train(self):
logger.info("Loading and preparing data...")
df = pd.read_csv(CSV_PATH)
# Prepare input features
base_features = ['TotalHeight']
X = df[base_features].values
self.scaler.fit(X)
X_scaled = self.scaler.transform(X)
# Train models for categorical columns
for col in self.categorical_columns:
self.encoders[col] = LabelEncoder()
encoded_values = self.encoders[col].fit_transform(df[col])
self.models[col] = RandomForestClassifier(n_estimators=100, random_state=42)
self.models[col].fit(X_scaled, encoded_values)
predictions = self.models[col].predict(X_scaled)
self.accuracies[col] = round(accuracy_score(encoded_values, predictions), 4)
# Train models for numerical columns
for col in self.numerical_columns:
self.models[col] = RandomForestRegressor(n_estimators=100, random_state=42)
self.models[col].fit(X_scaled, df[col])
predictions = self.models[col].predict(X_scaled)
self.accuracies[col] = round(r2_score(df[col], predictions), 4)
logger.info("Training completed successfully")
def predict(self, height, weight=None, body_type=None):
features = np.array([[height]])
features_scaled = self.scaler.transform(features)
predictions = {
"input": {
"height": float(height),
"unit": "cm",
"timestamp_utc": CURRENT_TIME,
"user": CURRENT_USER
},
"shirt_predictions": {},
"model_accuracies": {}
}
if weight is not None:
predictions["input"]["weight"] = float(weight)
predictions["input"]["weight_unit"] = "kg"
if body_type is not None:
predictions["input"]["body_type"] = body_type
# Predict categorical values
for col in self.categorical_columns:
pred = self.encoders[col].inverse_transform(
self.models[col].predict(features_scaled)
)[0]
predictions["shirt_predictions"][col] = {
"value": str(pred)
}
predictions["model_accuracies"][col] = self.accuracies[col]
# Predict numerical values
for col in self.numerical_columns:
pred = self.models[col].predict(features_scaled)[0]
predictions["shirt_predictions"][col] = {
"value": round(float(pred), 2),
"unit": self.units.get(col, "")
}
predictions["model_accuracies"][col] = self.accuracies[col]
return predictions
class BrandSizePredictor:
def __init__(self):
with open(SHIRT_SIZE_CHARTS_PATH, 'r') as f:
self.brand_charts = json.load(f)
def find_matching_sizes(self, measurements):
results = {
"input_measurements": {
"chest": measurements["chest"],
"waist": measurements["waist"],
"shoulder": measurements["shoulder"],
"unit": "cm"
},
"brand_recommendations": [],
"timestamp_utc": CURRENT_TIME,
"user": CURRENT_USER
}
for brand in self.brand_charts:
brand_result = {
"brand": brand["brand"],
"matching_sizes": []
}
for size in brand["sizes"]:
if (size["chest"][0] <= measurements["chest"] <= size["chest"][1] and
size["waist"][0] <= measurements["waist"] <= size["waist"][1] and
size["shoulder"][0] <= measurements["shoulder"] <= size["shoulder"][1]):
brand_result["matching_sizes"].append({
"size": size["label"],
"fit_details": {
"chest_range": size["chest"],
"waist_range": size["waist"],
"shoulder_range": size["shoulder"]
}
})
if brand_result["matching_sizes"]:
results["brand_recommendations"].append(brand_result)
return results
# Initialize predictors
shirt_predictor = ShirtPredictor()
shirt_predictor.train()
brand_predictor = BrandSizePredictor()
def predict_shirt_measurements(height, weight=None, body_type=None):
"""Gradio interface function for shirt predictions"""
try:
predictions = shirt_predictor.predict(height, weight, body_type)
return json.dumps(predictions, indent=2)
except Exception as e:
return json.dumps({
"error": str(e),
"timestamp_utc": CURRENT_TIME,
"user": CURRENT_USER
}, indent=2)
def predict_brand_sizes(chest, waist, shoulder):
"""Gradio interface function for brand size predictions"""
try:
measurements = {
"chest": float(chest),
"waist": float(waist),
"shoulder": float(shoulder)
}
predictions = brand_predictor.find_matching_sizes(measurements)
return json.dumps(predictions, indent=2)
except Exception as e:
return json.dumps({
"error": str(e),
"timestamp_utc": CURRENT_TIME,
"user": CURRENT_USER
}, indent=2)
# pants
class PantsPredictor:
def __init__(self):
self.models = {}
self.encoders = {}
self.scaler = StandardScaler()
self.categorical_columns = ['Size', 'Fit']
self.numerical_columns = [
'Waist', 'Hips', 'LegLength',
'WaistToKnee', 'Belly'
]
self.accuracies = {}
self.units = {
'Waist': 'cm',
'Hips': 'cm',
'LegLength': 'cm',
'WaistToKnee': 'cm',
'Belly': 'cm',
'Weight': 'kg',
'TotalHeight': 'cm'
}
def train(self):
logger.info("Loading and preparing pants prediction models...")
df = pd.read_csv(CSV_PATH)
# Prepare input features
base_features = ['TotalHeight']
X = df[base_features].values
self.scaler.fit(X)
X_scaled = self.scaler.transform(X)
# Train models for categorical columns
for col in self.categorical_columns:
self.encoders[col] = LabelEncoder()
encoded_values = self.encoders[col].fit_transform(df[col])
self.models[col] = RandomForestClassifier(n_estimators=100, random_state=42)
self.models[col].fit(X_scaled, encoded_values)
predictions = self.models[col].predict(X_scaled)
self.accuracies[col] = round(accuracy_score(encoded_values, predictions), 4)
# Train models for numerical columns
for col in self.numerical_columns:
self.models[col] = RandomForestRegressor(n_estimators=100, random_state=42)
self.models[col].fit(X_scaled, df[col])
predictions = self.models[col].predict(X_scaled)
self.accuracies[col] = round(r2_score(df[col], predictions), 4)
logger.info("Pants prediction models trained successfully")
def predict(self, height, weight=None, body_type=None):
features = np.array([[height]])
features_scaled = self.scaler.transform(features)
predictions = {
"input": {
"height": float(height),
"unit": "cm",
"timestamp_utc": CURRENT_TIME,
"user": CURRENT_USER
},
"pants_predictions": {},
"model_accuracies": {}
}
if weight is not None:
predictions["input"]["weight"] = float(weight)
predictions["input"]["weight_unit"] = "kg"
if body_type is not None:
predictions["input"]["body_type"] = body_type
# Predict categorical values
for col in self.categorical_columns:
pred = self.encoders[col].inverse_transform(
self.models[col].predict(features_scaled)
)[0]
predictions["pants_predictions"][col] = {
"value": str(pred)
}
predictions["model_accuracies"][col] = self.accuracies[col]
# Predict numerical values
for col in self.numerical_columns:
pred = self.models[col].predict(features_scaled)[0]
predictions["pants_predictions"][col] = {
"value": round(float(pred), 2),
"unit": self.units.get(col, "")
}
predictions["model_accuracies"][col] = self.accuracies[col]
return predictions
class PantsSizePredictor:
def __init__(self, size_charts_path=PANTS_SIZE_CHARTS_PATH):
try:
with open(size_charts_path, 'r') as f:
self.brand_charts = json.load(f)
logger.info(f"Successfully loaded {len(self.brand_charts)} brands from size charts")
# Add debug logging for loaded size charts
for brand in self.brand_charts:
logger.info(f"Loaded size chart for {brand['brand']}")
except Exception as e:
logger.error(f"Failed to load pants size charts: {str(e)}")
self.brand_charts = []
def find_matching_sizes(self, measurements):
logger.info(f"Finding sizes for measurements: {measurements}")
results = {
"input_measurements": {
"waist": measurements["waist"],
"hips": measurements["hips"],
"leg_length": measurements["leg_length"],
"unit": "cm",
"timestamp_utc": CURRENT_TIME,
"user": CURRENT_USER
},
"brand_recommendations": []
}
for brand in self.brand_charts:
brand_result = {
"brand": brand["brand"],
"matching_sizes": []
}
for size in brand["sizes"]:
# Add tolerance of ±2cm for better matching
waist_min = size["waist"][0] - 2
waist_max = size["waist"][1] + 2
hips_min = size["hips"][0] - 2
hips_max = size["hips"][1] + 2
leg_min = size["leg_length"][0] - 2
leg_max = size["leg_length"][1] + 2
# Debug logging for size checks
logger.debug(f"""
Checking {brand['brand']} size {size['label']}:
Waist: {measurements['waist']} in range {waist_min}-{waist_max}
Hips: {measurements['hips']} in range {hips_min}-{hips_max}
Leg: {measurements['leg_length']} in range {leg_min}-{leg_max}
""")
# Check if measurements fall within the size ranges (with tolerance)
if (waist_min <= measurements["waist"] <= waist_max and
hips_min <= measurements["hips"] <= hips_max and
leg_min <= measurements["leg_length"] <= leg_max):
size_match = {
"size": size["label"],
"fit_details": {
"waist_range": f"{size['waist'][0]}-{size['waist'][1]} cm",
"hips_range": f"{size['hips'][0]}-{size['hips'][1]} cm",
"leg_length_range": f"{size['leg_length'][0]}-{size['leg_length'][1]} cm"
},
"fit_quality": {
"waist": "Perfect" if size["waist"][0] <= measurements["waist"] <= size["waist"][1] else "Slightly loose/tight",
"hips": "Perfect" if size["hips"][0] <= measurements["hips"] <= size["hips"][1] else "Slightly loose/tight",
"leg_length": "Perfect" if size["leg_length"][0] <= measurements["leg_length"] <= size["leg_length"][1] else "Slightly long/short"
}
}
brand_result["matching_sizes"].append(size_match)
logger.info(f"Found matching size {size['label']} for {brand['brand']}")
if brand_result["matching_sizes"]:
results["brand_recommendations"].append(brand_result)
# Add debugging information
if not results["brand_recommendations"]:
logger.warning(f"No matching sizes found for measurements: {measurements}")
results["debug_info"] = {
"message": "No exact matches found. Consider these suggestions:",
"suggestions": [
"Try measurements within these ranges:",
"Waist: 72-91 cm",
"Hips: 90-110 cm",
"Leg Length: 97-106 cm"
],
"closest_matches": self._find_closest_matches(measurements)
}
return results
def _find_closest_matches(self, measurements):
closest_matches = []
for brand in self.brand_charts:
for size in brand["sizes"]:
# Calculate how close this size is to the measurements
waist_diff = min(abs(measurements["waist"] - size["waist"][0]),
abs(measurements["waist"] - size["waist"][1]))
hips_diff = min(abs(measurements["hips"] - size["hips"][0]),
abs(measurements["hips"] - size["hips"][1]))
leg_diff = min(abs(measurements["leg_length"] - size["leg_length"][0]),
abs(measurements["leg_length"] - size["leg_length"][1]))
if waist_diff <= 5 and hips_diff <= 5 and leg_diff <= 5:
closest_matches.append({
"brand": brand["brand"],
"size": size["label"],
"adjustments_needed": {
"waist": f"{waist_diff:+.1f} cm",
"hips": f"{hips_diff:+.1f} cm",
"leg_length": f"{leg_diff:+.1f} cm"
}
})
return closest_matches[:3] # Return top 3 closest matches
# Initialize pants predictors
pants_predictor = PantsPredictor()
pants_predictor.train()
pants_size_predictor = PantsSizePredictor()
def predict_pants_measurements(height, weight=None, body_type=None):
"""Gradio interface function for pants predictions based on height"""
try:
predictions = pants_predictor.predict(height, weight, body_type)
return json.dumps(predictions, indent=2)
except Exception as e:
return json.dumps({
"error": str(e),
"timestamp_utc": CURRENT_TIME,
"user": CURRENT_USER
}, indent=2)
def predict_pants_sizes(waist, leg_length, hips):
"""Gradio interface function for pants size predictions"""
try:
measurements = {
"waist": float(waist),
"leg_length": float(leg_length),
"hips": float(hips)
}
predictions = pants_size_predictor.find_matching_sizes(measurements)
return json.dumps(predictions, indent=2)
except Exception as e:
return json.dumps({
"error": str(e),
"timestamp_utc": CURRENT_TIME,
"user": CURRENT_USER
}, indent=2)
def format_shirt_predictions(predictions):
formatted = "### Shirt Measurements Predictions\n"
formatted += f"**Height:** {predictions['input']['height']} cm\n"
if 'weight' in predictions['input']:
formatted += f"**Weight:** {predictions['input']['weight']} kg\n"
if 'body_type' in predictions['input']:
formatted += f"**Body Type:** {predictions['input']['body_type']}\n"
formatted += "\n**Predictions:**\n"
for key, value in predictions['shirt_predictions'].items():
formatted += f"- **{key}:** {value['value']} {value.get('unit', '')}\n"
return formatted
def format_brand_predictions(predictions):
formatted = "### Brand Size Recommendations\n"
formatted += f"**Chest:** {predictions['input_measurements']['chest']} cm\n"
formatted += f"**Waist:** {predictions['input_measurements']['waist']} cm\n"
formatted += f"**Shoulder:** {predictions['input_measurements']['shoulder']} cm\n"
formatted += "\n**Recommendations:**\n"
for brand in predictions['brand_recommendations']:
formatted += f"- **Brand:** {brand['brand']}\n"
for size in brand['matching_sizes']:
formatted += f" - **Size:** {size['size']}\n"
formatted += f" - **Chest Range:** {size['fit_details']['chest_range']}\n"
formatted += f" - **Waist Range:** {size['fit_details']['waist_range']}\n"
formatted += f" - **Shoulder Range:** {size['fit_details']['shoulder_range']}\n"
return formatted
def format_pants_predictions(predictions):
formatted = "### Pants Measurements Predictions\n"
formatted += f"**Height:** {predictions['input']['height']} cm\n"
if 'weight' in predictions['input']:
formatted += f"**Weight:** {predictions['input']['weight']} kg\n"
if 'body_type' in predictions['input']:
formatted += f"**Body Type:** {predictions['input']['body_type']}\n"
formatted += "\n**Predictions:**\n"
for key, value in predictions['pants_predictions'].items():
formatted += f"- **{key}:** {value['value']} {value.get('unit', '')}\n"
return formatted
def format_pants_brand_predictions(predictions):
formatted = "### Pants Size Recommendations\n"
formatted += f"**Waist:** {predictions['input_measurements']['waist']} cm\n"
formatted += f"**Hips:** {predictions['input_measurements']['hips']} cm\n"
formatted += f"**Leg Length:** {predictions['input_measurements']['leg_length']} cm\n"
formatted += "\n**Recommendations:**\n"
for brand in predictions['brand_recommendations']:
formatted += f"- **Brand:** {brand['brand']}\n"
for size in brand['matching_sizes']:
formatted += f" - **Size:** {size['size']}\n"
formatted += f" - **Waist Range:** {size['fit_details']['waist_range']}\n"
formatted += f" - **Hips Range:** {size['fit_details']['hips_range']}\n"
formatted += f" - **Leg Length Range:** {size['fit_details']['leg_length_range']}\n"
return formatted
# Update Gradio interface to use formatted predictions
with gr.Blocks(title="Body Measurements Predictor") as demo:
gr.Markdown(f"""
# Body Measurements Predictor
Created by: {CURRENT_USER}
Last Updated: {CURRENT_TIME}
""")
with gr.Tabs():
# First Tab - Shirt Measurements
with gr.Tab("Shirt Measurements"):
with gr.Row():
with gr.Column():
height_input = gr.Number(
label="Height (cm) *",
minimum=50,
maximum=250,
step=1,
value=170
)
weight_input = gr.Number(
label="Weight (kg) (optional)",
minimum=30,
maximum=200,
step=0.1
)
body_type_input = gr.Dropdown(
label="Body Type (optional)",
choices=["Slim", "Regular", "Athletic", "Large"],
value=None
)
predict_button = gr.Button("Predict Shirt Measurements")
with gr.Column():
output_markdown = gr.Markdown(label="Shirt Measurements Predictions")
with gr.Column(scale=2, min_width=300):
model3d = gr.Model3D(
value="jacket.glb", # Path to your .glb file on server
clear_color=[0.0, 0.0, 0.0, 0.0], # Transparent background
camera_position=[0, 0, 5], # Initial camera position
visible=False # Initially hidden
)
def update_model_visibility(height, weight, body_type):
predictions = format_shirt_predictions(
json.loads(predict_shirt_measurements(height, weight, body_type))
)
return predictions, gr.update(visible=True)
predict_button.click(
fn=update_model_visibility,
inputs=[height_input, weight_input, body_type_input],
outputs=[output_markdown, model3d]
)
gr.Markdown("""
### Instructions:
1. Enter your height (required)
2. Optionally enter your weight and select your body type
3. Click "Predict Shirt Measurements" to get detailed predictions
""")
# Second Tab - Brand Size Finder (Shirts)
with gr.Tab("Shirt Size Finder"):
with gr.Row():
with gr.Column():
chest_input = gr.Number(
label="Chest Circumference (cm)",
minimum=80,
maximum=120,
step=0.5,
value=95
)
waist_input = gr.Number(
label="Waist Circumference (cm)",
minimum=60,
maximum=110,
step=0.5,
value=80
)
shoulder_input = gr.Number(
label="Shoulder Width (cm)",
minimum=35,
maximum=55,
step=0.5,
value=43
)
brand_predict_button = gr.Button("Find Matching Sizes")
with gr.Column():
brand_output_markdown = gr.Markdown(label="Brand Size Recommendations")
with gr.Column(scale=2, min_width=300):
model3d = gr.Model3D(
value="jacket.glb", # Path to your .glb file on server
clear_color=[0.0, 0.0, 0.0, 0.0], # Transparent background
camera_position=[0, 0, 5], # Initial camera position
visible=False # Initially hidden
)
def update_model_visibility(chest, waist, shoulder):
predictions = format_brand_predictions(
json.loads(predict_brand_sizes(chest, waist, shoulder))
)
return predictions, gr.update(visible=True)
brand_predict_button.click(
fn=update_model_visibility,
inputs=[chest_input, waist_input, shoulder_input],
outputs=[brand_output_markdown, model3d]
)
gr.Markdown("""
### Instructions:
1. Enter your measurements:
- Chest circumference
- Waist circumference
- Shoulder width
2. Click "Find Matching Sizes" to see which sizes fit you across different brands
""")
# Third Tab - Pants Measurements
with gr.Tab("Pants Measurements"):
with gr.Row():
with gr.Column():
pants_height_input = gr.Number(
label="Height (cm) *",
minimum=50,
maximum=250,
step=1,
value=170
)
pants_weight_input = gr.Number(
label="Weight (kg) (optional)",
minimum=30,
maximum=200,
step=0.1
)
pants_body_type_input = gr.Dropdown(
label="Body Type (optional)",
choices=["Slim", "Regular", "Athletic", "Large"],
value=None
)
pants_predict_button = gr.Button("Predict Pants Measurements")
with gr.Column():
pants_output_markdown = gr.Markdown(label="Pants Measurements Predictions")
with gr.Column():
model3d = gr.Model3D(
value="pants.glb", # Path to your .glb file on server
clear_color=[0.0, 0.0, 0.0, 0.0], # Transparent background
camera_position=[0, 0, 5], # Initial camera position
visible=False # Initially hidden
)
def update_model_visibility(height, weight, body_type):
predictions = format_pants_predictions(
json.loads(predict_pants_measurements(height, weight, body_type))
)
return predictions, gr.update(visible=True)
pants_predict_button.click(
fn=update_model_visibility,
inputs=[pants_height_input, pants_weight_input, pants_body_type_input],
outputs=[pants_output_markdown, model3d]
)
gr.Markdown("""
### Instructions:
1. Enter your height (required)
2. Optionally enter your weight and select your body type
3. Click "Predict Pants Measurements" to get detailed predictions
""")
# Fourth Tab - Pants Size Finder
with gr.Tab("Pants Size Finder"):
with gr.Row():
with gr.Column():
pants_waist_input = gr.Number(
label="Waist Circumference (cm)",
minimum=60,
maximum=120,
step=0.5,
value=80
)
pants_leg_input = gr.Number(
label="Leg Length (cm)",
minimum=60,
maximum=120,
step=0.5,
value=98
)
pants_hips_input = gr.Number(
label="Hips Circumference (cm)",
minimum=80,
maximum=140,
step=0.5,
value=102
)
pants_brand_predict_button = gr.Button("Find Matching Pants Sizes")
with gr.Column():
pants_brand_output_markdown = gr.Markdown(label="Pants Size Recommendations")
with gr.Column():
model3d = gr.Model3D(
value="pants.glb", # Path to your .glb file on server
clear_color=[0.0, 0.0, 0.0, 0.0], # Transparent background
camera_position=[0, 0, 5], # Initial camera position
visible=False # Initially hidden
)
def update_model_visibility(waist, leg_length, hips):
predictions = format_pants_brand_predictions(
json.loads(predict_pants_sizes(waist, leg_length, hips))
)
return predictions, gr.update(visible=True) # Fixed syntax error here
pants_brand_predict_button.click(
fn=update_model_visibility,
inputs=[pants_waist_input, pants_leg_input, pants_hips_input],
outputs=[pants_brand_output_markdown, model3d]
)
gr.Markdown("""
### Instructions:
1. Enter your measurements:
- Waist circumference
- Leg length
- Hips circumference
2. Click "Find Matching Pants Sizes" to see which sizes fit you across different brands
""")
if __name__ == "__main__":
logger.info("Starting Gradio interface...")
demo.launch()