Ali Mohsin
commited on
Commit
Β·
a13f0b7
1
Parent(s):
dcfea2b
updates 9.0
Browse files
app.py
CHANGED
|
@@ -69,7 +69,8 @@ class GPTOSSSizeRecommender:
|
|
| 69 |
self.tokenizer = AutoTokenizer.from_pretrained(
|
| 70 |
self.model_name,
|
| 71 |
trust_remote_code=True,
|
| 72 |
-
use_fast=False
|
|
|
|
| 73 |
)
|
| 74 |
|
| 75 |
# Add padding token if not present
|
|
@@ -93,7 +94,8 @@ class GPTOSSSizeRecommender:
|
|
| 93 |
# Load model with 8-bit
|
| 94 |
self.model = AutoModelForCausalLM.from_pretrained(
|
| 95 |
self.model_name,
|
| 96 |
-
**model_kwargs
|
|
|
|
| 97 |
)
|
| 98 |
print("β
Model loaded with 8-bit quantization")
|
| 99 |
except Exception as e:
|
|
@@ -107,7 +109,8 @@ class GPTOSSSizeRecommender:
|
|
| 107 |
}
|
| 108 |
self.model = AutoModelForCausalLM.from_pretrained(
|
| 109 |
self.model_name,
|
| 110 |
-
**model_kwargs
|
|
|
|
| 111 |
)
|
| 112 |
print("β
Model loaded with bfloat16")
|
| 113 |
else:
|
|
@@ -118,7 +121,8 @@ class GPTOSSSizeRecommender:
|
|
| 118 |
# Load model
|
| 119 |
self.model = AutoModelForCausalLM.from_pretrained(
|
| 120 |
self.model_name,
|
| 121 |
-
**model_kwargs
|
|
|
|
| 122 |
)
|
| 123 |
|
| 124 |
if self.device == "cpu":
|
|
@@ -242,83 +246,66 @@ class GPTOSSSizeRecommender:
|
|
| 242 |
gender = user_data.get('gender', 'unisex')
|
| 243 |
estimated_measurements = self.estimate_missing_measurements(user_data, gender)
|
| 244 |
|
| 245 |
-
|
| 246 |
-
|
| 247 |
-
**CUSTOMER PROFILE:**
|
| 248 |
-
Gender/Body Type: {user_data.get('body_type', 'Not specified')} / {gender}
|
| 249 |
-
Height: {estimated_measurements.get('height', 'Not provided')} inches
|
| 250 |
-
Weight: {estimated_measurements.get('weight', 'Not provided')} lbs
|
| 251 |
-
|
| 252 |
-
**BODY MEASUREMENTS (in inches):**
|
| 253 |
-
- Chest/Bust: {estimated_measurements.get('chest', 0):.1f} {'(estimated)' if user_data.get('chest', 0) == 0 and estimated_measurements.get('chest', 0) > 0 else ''}
|
| 254 |
-
- Shoulder Width: {estimated_measurements.get('shoulder_width', 0):.1f} {'(estimated)' if user_data.get('shoulder_width', 0) == 0 and estimated_measurements.get('shoulder_width', 0) > 0 else ''}
|
| 255 |
-
- Sleeve Length: {estimated_measurements.get('sleeve_length', 0):.1f} {'(estimated)' if user_data.get('sleeve_length', 0) == 0 and estimated_measurements.get('sleeve_length', 0) > 0 else ''}
|
| 256 |
-
- Neck Circumference: {estimated_measurements.get('neck_circumference', 0):.1f} {'(estimated)' if user_data.get('neck_circumference', 0) == 0 and estimated_measurements.get('neck_circumference', 0) > 0 else ''}
|
| 257 |
-
- Shirt Length: {estimated_measurements.get('shirt_length', 0):.1f} {'(estimated)' if user_data.get('shirt_length', 0) == 0 and estimated_measurements.get('shirt_length', 0) > 0 else ''}
|
| 258 |
-
- Armhole Size: {estimated_measurements.get('armhole_size', 0):.1f} {'(estimated)' if user_data.get('armhole_size', 0) == 0 and estimated_measurements.get('armhole_size', 0) > 0 else ''}
|
| 259 |
-
- Waist: {estimated_measurements.get('waist', 0):.1f} {'(estimated)' if user_data.get('waist', 0) == 0 and estimated_measurements.get('waist', 0) > 0 else ''}
|
| 260 |
-
- Inseam: {estimated_measurements.get('inseam', 0):.1f} {'(estimated)' if user_data.get('inseam', 0) == 0 and estimated_measurements.get('inseam', 0) > 0 else ''}
|
| 261 |
-
- Thigh Circumference: {estimated_measurements.get('thigh_circumference', 0):.1f} {'(estimated)' if user_data.get('thigh_circumference', 0) == 0 and estimated_measurements.get('thigh_circumference', 0) > 0 else ''}
|
| 262 |
-
|
| 263 |
-
**GARMENT DETAILS:**
|
| 264 |
-
- Product: {garment_data.get('product_name', 'Not specified')}
|
| 265 |
-
- Brand: {garment_data.get('brand', 'Not specified')}
|
| 266 |
-
- Category: {garment_data.get('category', 'Not specified')}
|
| 267 |
-
- Available Sizes: {', '.join(garment_data.get('available_sizes', []))}
|
| 268 |
-
|
| 269 |
-
**GARMENT SIZE SPECIFICATIONS (in inches):**"""
|
| 270 |
-
|
| 271 |
-
# Add size measurements for each available size
|
| 272 |
for size in garment_data.get('available_sizes', []):
|
| 273 |
measurements = garment_data.get(f'{size.lower()}_measurements', {})
|
| 274 |
if measurements:
|
| 275 |
-
|
| 276 |
-
|
| 277 |
-
|
| 278 |
-
prompt += f"\n - {measurement.title()}: {value} inches"
|
| 279 |
|
| 280 |
-
|
| 281 |
|
| 282 |
-
|
| 283 |
-
|
| 284 |
-
|
| 285 |
-
|
| 286 |
-
|
| 287 |
-
|
| 288 |
-
6. **Tolerance Analysis**: Account for fabric stretch, fit preferences, and wearing comfort
|
| 289 |
|
| 290 |
-
|
| 291 |
-
|
| 292 |
-
|
| 293 |
-
|
|
|
|
|
|
|
| 294 |
|
| 295 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 296 |
|
| 297 |
-
|
| 298 |
-
|
| 299 |
-
|
| 300 |
-
- Shoulder: [Analysis with specific numbers]
|
| 301 |
-
- Length: [Analysis with specific numbers]
|
| 302 |
|
| 303 |
-
|
| 304 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 305 |
|
| 306 |
-
|
| 307 |
-
|
| 308 |
-
|
| 309 |
-
- Style Appropriateness: [Assessment]
|
| 310 |
|
| 311 |
-
|
| 312 |
-
|
|
|
|
|
|
|
| 313 |
|
| 314 |
-
|
| 315 |
-
[
|
|
|
|
|
|
|
| 316 |
|
| 317 |
-
|
| 318 |
-
|
| 319 |
|
| 320 |
-
|
| 321 |
-
"""
|
| 322 |
|
| 323 |
return prompt
|
| 324 |
|
|
@@ -346,13 +333,15 @@ Reasoning: high
|
|
| 346 |
with torch.no_grad():
|
| 347 |
outputs = self.model.generate(
|
| 348 |
**inputs,
|
| 349 |
-
max_new_tokens=
|
| 350 |
-
temperature=0.
|
| 351 |
do_sample=True,
|
| 352 |
-
top_p=0.
|
|
|
|
| 353 |
pad_token_id=self.tokenizer.eos_token_id,
|
| 354 |
eos_token_id=self.tokenizer.eos_token_id,
|
| 355 |
-
repetition_penalty=1.
|
|
|
|
| 356 |
)
|
| 357 |
|
| 358 |
# Decode response
|
|
@@ -364,10 +353,64 @@ Reasoning: high
|
|
| 364 |
else:
|
| 365 |
response = generated_text.strip()
|
| 366 |
|
|
|
|
|
|
|
|
|
|
| 367 |
return response if response else "No response generated"
|
| 368 |
|
| 369 |
except Exception as e:
|
| 370 |
return f"β Model Error: {str(e)}\nPlease try again or restart the application."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 371 |
|
| 372 |
def recommend_size(self, user_data: Dict, garment_data: Dict, api_key: str = None) -> str:
|
| 373 |
"""Main function to get size recommendation"""
|
|
@@ -403,6 +446,14 @@ def predict_size(
|
|
| 403 |
) -> str:
|
| 404 |
"""Enhanced prediction function with robust input handling"""
|
| 405 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 406 |
try:
|
| 407 |
# Parse all measurements with units
|
| 408 |
user_data = {
|
|
@@ -449,10 +500,29 @@ def predict_size(
|
|
| 449 |
if total_measurements < 2:
|
| 450 |
return "β οΈ Please provide at least 2 body measurements for accurate recommendations."
|
| 451 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 452 |
# Get recommendation
|
| 453 |
recommendation = recommender.recommend_size(user_data, garment_data)
|
| 454 |
|
| 455 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 456 |
|
| 457 |
except Exception as e:
|
| 458 |
return f"β Processing Error: {str(e)}\nPlease check your inputs and try again."
|
|
|
|
| 69 |
self.tokenizer = AutoTokenizer.from_pretrained(
|
| 70 |
self.model_name,
|
| 71 |
trust_remote_code=True,
|
| 72 |
+
use_fast=False,
|
| 73 |
+
cache_dir="/tmp/huggingface_cache"
|
| 74 |
)
|
| 75 |
|
| 76 |
# Add padding token if not present
|
|
|
|
| 94 |
# Load model with 8-bit
|
| 95 |
self.model = AutoModelForCausalLM.from_pretrained(
|
| 96 |
self.model_name,
|
| 97 |
+
**model_kwargs,
|
| 98 |
+
cache_dir="/tmp/huggingface_cache"
|
| 99 |
)
|
| 100 |
print("β
Model loaded with 8-bit quantization")
|
| 101 |
except Exception as e:
|
|
|
|
| 109 |
}
|
| 110 |
self.model = AutoModelForCausalLM.from_pretrained(
|
| 111 |
self.model_name,
|
| 112 |
+
**model_kwargs,
|
| 113 |
+
cache_dir="/tmp/huggingface_cache"
|
| 114 |
)
|
| 115 |
print("β
Model loaded with bfloat16")
|
| 116 |
else:
|
|
|
|
| 121 |
# Load model
|
| 122 |
self.model = AutoModelForCausalLM.from_pretrained(
|
| 123 |
self.model_name,
|
| 124 |
+
**model_kwargs,
|
| 125 |
+
cache_dir="/tmp/huggingface_cache"
|
| 126 |
)
|
| 127 |
|
| 128 |
if self.device == "cpu":
|
|
|
|
| 246 |
gender = user_data.get('gender', 'unisex')
|
| 247 |
estimated_measurements = self.estimate_missing_measurements(user_data, gender)
|
| 248 |
|
| 249 |
+
# Build size comparison table
|
| 250 |
+
size_comparisons = []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 251 |
for size in garment_data.get('available_sizes', []):
|
| 252 |
measurements = garment_data.get(f'{size.lower()}_measurements', {})
|
| 253 |
if measurements:
|
| 254 |
+
size_comparisons.append(f"{size}: Chest={measurements.get('chest', 'N/A')}, Waist={measurements.get('waist', 'N/A')}, Length={measurements.get('length', 'N/A')}")
|
| 255 |
+
|
| 256 |
+
prompt = f"""<system>You are a professional clothing size recommendation assistant. You must provide clear, structured recommendations following the exact format specified.</system>
|
|
|
|
| 257 |
|
| 258 |
+
<task>Analyze the customer's measurements against the garment specifications and recommend the best size.</task>
|
| 259 |
|
| 260 |
+
<customer_info>
|
| 261 |
+
- Gender: {gender}
|
| 262 |
+
- Body Type: {user_data.get('body_type', 'Regular')}
|
| 263 |
+
- Height: {estimated_measurements.get('height', 0):.0f} inches
|
| 264 |
+
- Weight: {estimated_measurements.get('weight', 0):.0f} lbs
|
| 265 |
+
</customer_info>
|
|
|
|
| 266 |
|
| 267 |
+
<customer_measurements>
|
| 268 |
+
- Chest: {estimated_measurements.get('chest', 0):.0f}" (User Provided: {'Yes' if user_data.get('chest', 0) > 0 else 'No'})
|
| 269 |
+
- Waist: {estimated_measurements.get('waist', 0):.0f}" (User Provided: {'Yes' if user_data.get('waist', 0) > 0 else 'No'})
|
| 270 |
+
- Shoulder: {estimated_measurements.get('shoulder_width', 0):.0f}" (User Provided: {'Yes' if user_data.get('shoulder_width', 0) > 0 else 'No'})
|
| 271 |
+
- Length Preference: {estimated_measurements.get('shirt_length', 0):.0f}" (User Provided: {'Yes' if user_data.get('shirt_length', 0) > 0 else 'No'})
|
| 272 |
+
</customer_measurements>
|
| 273 |
|
| 274 |
+
<garment_info>
|
| 275 |
+
- Product: {garment_data.get('product_name', 'Not specified')}
|
| 276 |
+
- Brand: {garment_data.get('brand', 'Not specified')}
|
| 277 |
+
- Category: {garment_data.get('category', 'Not specified')}
|
| 278 |
+
</garment_info>
|
| 279 |
|
| 280 |
+
<available_sizes>
|
| 281 |
+
{chr(10).join(size_comparisons)}
|
| 282 |
+
</available_sizes>
|
|
|
|
|
|
|
| 283 |
|
| 284 |
+
<instructions>
|
| 285 |
+
1. Compare customer measurements to each size
|
| 286 |
+
2. Find the best match considering chest as priority, then waist, then length
|
| 287 |
+
3. Calculate fit tolerance (2-3 inches for comfort)
|
| 288 |
+
4. Consider if estimated measurements affect confidence
|
| 289 |
+
5. Provide your response in EXACTLY this format:
|
| 290 |
|
| 291 |
+
RECOMMENDED SIZE: [Choose one size]
|
| 292 |
+
CONFIDENCE: [Number 1-100]%
|
| 293 |
+
ALTERNATIVE: [Second best size or "None"]
|
|
|
|
| 294 |
|
| 295 |
+
FIT ANALYSIS:
|
| 296 |
+
β Chest fit: [Customer chest] vs Size [X] chest [Y] = [Perfect/Good/Tight/Loose]
|
| 297 |
+
β Waist fit: [Customer waist] vs Size [X] waist [Y] = [Perfect/Good/Tight/Loose]
|
| 298 |
+
β Length fit: [Assessment based on height and garment length]
|
| 299 |
|
| 300 |
+
KEY POINTS:
|
| 301 |
+
β’ [Most important fit consideration]
|
| 302 |
+
β’ [Second important point]
|
| 303 |
+
β’ [Any concerns or adjustments needed]
|
| 304 |
|
| 305 |
+
RECOMMENDATION: [One sentence summary, e.g. "Size M will provide the best overall fit with comfortable room in the chest and proper length."]
|
| 306 |
+
</instructions>
|
| 307 |
|
| 308 |
+
Provide your analysis now:"""
|
|
|
|
| 309 |
|
| 310 |
return prompt
|
| 311 |
|
|
|
|
| 333 |
with torch.no_grad():
|
| 334 |
outputs = self.model.generate(
|
| 335 |
**inputs,
|
| 336 |
+
max_new_tokens=400,
|
| 337 |
+
temperature=0.3,
|
| 338 |
do_sample=True,
|
| 339 |
+
top_p=0.95,
|
| 340 |
+
top_k=50,
|
| 341 |
pad_token_id=self.tokenizer.eos_token_id,
|
| 342 |
eos_token_id=self.tokenizer.eos_token_id,
|
| 343 |
+
repetition_penalty=1.05,
|
| 344 |
+
num_beams=1
|
| 345 |
)
|
| 346 |
|
| 347 |
# Decode response
|
|
|
|
| 353 |
else:
|
| 354 |
response = generated_text.strip()
|
| 355 |
|
| 356 |
+
# Format response
|
| 357 |
+
response = self.format_response(response)
|
| 358 |
+
|
| 359 |
return response if response else "No response generated"
|
| 360 |
|
| 361 |
except Exception as e:
|
| 362 |
return f"β Model Error: {str(e)}\nPlease try again or restart the application."
|
| 363 |
+
|
| 364 |
+
def format_response(self, response: str) -> str:
|
| 365 |
+
"""Format and clean up the model response"""
|
| 366 |
+
# Clean up common issues
|
| 367 |
+
response = response.strip()
|
| 368 |
+
|
| 369 |
+
# If response doesn't follow format, try to extract key information
|
| 370 |
+
if "RECOMMENDED SIZE:" not in response:
|
| 371 |
+
# Try to extract size recommendation from unstructured text
|
| 372 |
+
import re
|
| 373 |
+
|
| 374 |
+
# Look for size mentions
|
| 375 |
+
size_pattern = r'\b(XS|S|M|L|XL|XXL|XXXL)\b'
|
| 376 |
+
sizes_found = re.findall(size_pattern, response.upper())
|
| 377 |
+
|
| 378 |
+
if sizes_found:
|
| 379 |
+
# Create structured response
|
| 380 |
+
formatted = f"""π― **RECOMMENDED SIZE: {sizes_found[0]}**
|
| 381 |
+
π **CONFIDENCE: 75%**
|
| 382 |
+
|
| 383 |
+
π **ANALYSIS:**
|
| 384 |
+
{response[:500]}...
|
| 385 |
+
|
| 386 |
+
β
**RECOMMENDATION:**
|
| 387 |
+
Based on the analysis, size {sizes_found[0]} is recommended."""
|
| 388 |
+
return formatted
|
| 389 |
+
|
| 390 |
+
# Clean up formatting
|
| 391 |
+
lines = response.split('\n')
|
| 392 |
+
cleaned_lines = []
|
| 393 |
+
|
| 394 |
+
for line in lines:
|
| 395 |
+
line = line.strip()
|
| 396 |
+
if line:
|
| 397 |
+
# Format headers
|
| 398 |
+
if line.startswith("RECOMMENDED SIZE:"):
|
| 399 |
+
line = f"π― **{line}**"
|
| 400 |
+
elif line.startswith("CONFIDENCE:"):
|
| 401 |
+
line = f"π **{line}**"
|
| 402 |
+
elif line.startswith("ALTERNATIVE:"):
|
| 403 |
+
line = f"π **{line}**"
|
| 404 |
+
elif line.startswith("FIT ANALYSIS:"):
|
| 405 |
+
line = f"\nπ **{line}**"
|
| 406 |
+
elif line.startswith("KEY POINTS:"):
|
| 407 |
+
line = f"\nπ **{line}**"
|
| 408 |
+
elif line.startswith("RECOMMENDATION:"):
|
| 409 |
+
line = f"\nβ
**{line}**"
|
| 410 |
+
|
| 411 |
+
cleaned_lines.append(line)
|
| 412 |
+
|
| 413 |
+
return '\n'.join(cleaned_lines)
|
| 414 |
|
| 415 |
def recommend_size(self, user_data: Dict, garment_data: Dict, api_key: str = None) -> str:
|
| 416 |
"""Main function to get size recommendation"""
|
|
|
|
| 446 |
) -> str:
|
| 447 |
"""Enhanced prediction function with robust input handling"""
|
| 448 |
|
| 449 |
+
# Check if model is loaded
|
| 450 |
+
if not recommender.model_loaded:
|
| 451 |
+
return """β³ **AI Model is Loading...**
|
| 452 |
+
|
| 453 |
+
Please wait a moment while the AI model initializes. This may take 1-2 minutes on first use.
|
| 454 |
+
|
| 455 |
+
Once loaded, click 'Get My Perfect Size' again!"""
|
| 456 |
+
|
| 457 |
try:
|
| 458 |
# Parse all measurements with units
|
| 459 |
user_data = {
|
|
|
|
| 500 |
if total_measurements < 2:
|
| 501 |
return "β οΈ Please provide at least 2 body measurements for accurate recommendations."
|
| 502 |
|
| 503 |
+
# Show processing message
|
| 504 |
+
processing_msg = """π **Analyzing your measurements...**
|
| 505 |
+
|
| 506 |
+
Our AI is comparing your measurements with the garment specifications to find your perfect fit.
|
| 507 |
+
|
| 508 |
+
This usually takes 5-10 seconds."""
|
| 509 |
+
|
| 510 |
# Get recommendation
|
| 511 |
recommendation = recommender.recommend_size(user_data, garment_data)
|
| 512 |
|
| 513 |
+
# Add visual separator
|
| 514 |
+
final_output = f"""
|
| 515 |
+
{recommendation}
|
| 516 |
+
|
| 517 |
+
---
|
| 518 |
+
|
| 519 |
+
π‘ **Shopping Tips:**
|
| 520 |
+
- If between sizes, consider the fabric (stretchy vs rigid)
|
| 521 |
+
- Check the brand's return policy before ordering
|
| 522 |
+
- Save your measurements for future purchases
|
| 523 |
+
"""
|
| 524 |
+
|
| 525 |
+
return final_output
|
| 526 |
|
| 527 |
except Exception as e:
|
| 528 |
return f"β Processing Error: {str(e)}\nPlease check your inputs and try again."
|