Hashii1729 commited on
Commit
d67fe33
Β·
1 Parent(s): 17a42ab

Add dependencies for HuggingFace conversion and create test script

Browse files

- Updated requirements.txt to include necessary packages for HuggingFace model conversion, including transformers, torch, and related libraries.
- Added a new test script (test_hf_conversion.py) to verify the functionality of HuggingFace conversion, including import tests, pipeline creation, and basic functionality with a sample image.

Files changed (3) hide show
  1. fast.py +1093 -74
  2. requirements.txt +53 -3
  3. test_hf_conversion.py +130 -0
fast.py CHANGED
@@ -2,88 +2,1108 @@ from fastapi import FastAPI, HTTPException, UploadFile, File
2
  from fastapi.responses import JSONResponse, HTMLResponse, PlainTextResponse
3
  from pydantic import BaseModel
4
  from typing import List, Optional
5
- import requests
6
  import json
7
- import base64
8
  from PIL import Image
9
  import io
10
- import os
11
  import time
12
  import uvicorn
 
 
 
 
 
 
 
 
13
 
14
- app = FastAPI(title="Ollama Fashion Analyzer API", version="1.0.0")
15
 
16
- class OllamaFashionAnalyzer:
17
- def __init__(self, base_url=None):
18
- """Initialize Ollama client"""
19
- self.base_url = base_url or os.getenv("OLLAMA_BASE_URL", "http://localhost:11434")
20
- self.model = "llava:7b" # Using LLaVA for vision analysis
21
-
22
- def encode_image_from_bytes(self, image_bytes):
23
- """Encode image bytes to base64 for Ollama"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  image = Image.open(io.BytesIO(image_bytes))
25
-
26
  # Convert to RGB if necessary
27
  if image.mode != 'RGB':
28
  image = image.convert('RGB')
29
-
30
- # Convert to base64
31
- buffered = io.BytesIO()
32
- image.save(buffered, format="JPEG")
33
- img_str = base64.b64encode(buffered.getvalue()).decode()
34
-
35
- return img_str
36
-
37
  def analyze_clothing_from_bytes(self, image_bytes):
38
- """Detailed clothing analysis using Ollama from image bytes"""
39
-
40
- # Encode image
41
- image_b64 = self.encode_image_from_bytes(image_bytes)
42
-
43
- # Fashion analysis prompt
44
- prompt = """Analyze this clothing item in detail and provide information about:
45
-
46
- 1. GARMENT TYPE: What type of clothing is this?
47
- 2. COLORS: Primary and secondary colors
48
- 3. COLLAR/NECKLINE: Style of collar or neckline
49
- 4. SLEEVES: Sleeve type and length
50
- 5. PATTERN: Any patterns or designs
51
- 6. FIT: How does it fit (loose, fitted, etc.)
52
- 7. MATERIAL: Apparent fabric type
53
- 8. FEATURES: Buttons, pockets, zippers, etc.
54
- 9. STYLE: Fashion style category
55
- 10. OCCASION: Suitable occasions for wearing
56
-
57
- Be specific and detailed in your analysis."""
58
-
59
- # Make request to Ollama
60
- payload = {
61
- "model": self.model,
62
- "prompt": prompt,
63
- "images": [image_b64],
64
- "stream": False,
65
- "options": {
66
- "temperature": 0.2,
67
- "num_predict": 500
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  }
69
- }
70
-
 
 
 
 
 
 
71
  try:
72
- response = requests.post(
73
- f"{self.base_url}/api/generate",
74
- json=payload,
75
- timeout=120 # Increased timeout for vision models
76
- )
77
- response.raise_for_status()
78
-
79
- result = response.json()
80
- return result.get('response', 'No response received')
81
-
82
- except requests.exceptions.RequestException as e:
83
- return f"Error: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
 
85
  # Initialize analyzer
86
- analyzer = OllamaFashionAnalyzer()
87
 
88
  # Request/Response models
89
  class AnalysisResponse(BaseModel):
@@ -171,14 +1191,13 @@ async def analyze_image(file: UploadFile = File(...)):
171
  async def health_check():
172
  """Health check endpoint"""
173
  try:
174
- # Test Ollama connection
175
- response = requests.get(f"{analyzer.base_url}/api/tags", timeout=5)
176
- if response.status_code == 200:
177
- return {"status": "healthy", "ollama": "connected"}
178
  else:
179
- return {"status": "unhealthy", "ollama": "disconnected"}
180
- except:
181
- return {"status": "unhealthy", "ollama": "disconnected"}
182
 
183
  if __name__ == "__main__":
184
- uvicorn.run(app, host="0.0.0.0", port=7860)
 
2
  from fastapi.responses import JSONResponse, HTMLResponse, PlainTextResponse
3
  from pydantic import BaseModel
4
  from typing import List, Optional
 
5
  import json
 
6
  from PIL import Image
7
  import io
 
8
  import time
9
  import uvicorn
10
+ from transformers import AutoImageProcessor, AutoModelForObjectDetection, SwinModel, SwinConfig
11
+ from transformers.pipelines import pipeline
12
+ import torch
13
+ import torch.nn as nn
14
+ import torch.nn.functional as F
15
+ import torchvision.transforms as v2
16
+ from huggingface_hub import PyTorchModelHubMixin
17
+ import numpy as np
18
 
19
+ app = FastAPI(title="HuggingFace Fashion Analyzer API", version="1.0.0")
20
 
21
+ # Fashion Image Encoder class for yainage90 model
22
+ class ImageEncoder(nn.Module, PyTorchModelHubMixin):
23
+ def __init__(self, config):
24
+ super(ImageEncoder, self).__init__()
25
+ self.swin = SwinModel(config=config)
26
+ self.embedding_layer = nn.Linear(config.hidden_size, 128)
27
+
28
+ def forward(self, image_tensor):
29
+ features = self.swin(image_tensor).pooler_output
30
+ embeddings = self.embedding_layer(features)
31
+ embeddings = F.normalize(embeddings, p=2, dim=1)
32
+ return embeddings
33
+
34
+ class HuggingFaceFashionAnalyzer:
35
+ def __init__(self):
36
+ """Initialize specialized fashion models from yainage90"""
37
+ print("Loading yainage90 fashion models...")
38
+
39
+ self.device = "cuda" if torch.cuda.is_available() else "cpu"
40
+ print(f"Using device: {self.device}")
41
+
42
+ # Initialize yainage90 fashion object detection model
43
+ try:
44
+ self.detection_ckpt = 'yainage90/fashion-object-detection'
45
+ self.detection_processor = AutoImageProcessor.from_pretrained(self.detection_ckpt)
46
+ self.detection_model = AutoModelForObjectDetection.from_pretrained(self.detection_ckpt).to(self.device)
47
+ print("Fashion object detection model loaded successfully")
48
+ except Exception as e:
49
+ print(f"Error loading fashion detection model: {e}")
50
+ self.detection_model = None
51
+ self.detection_processor = None
52
+
53
+ # Initialize yainage90 fashion feature extractor
54
+ try:
55
+ self.encoder_ckpt = "yainage90/fashion-image-feature-extractor"
56
+ self.encoder_config = SwinConfig.from_pretrained(self.encoder_ckpt)
57
+ self.encoder_image_processor = AutoImageProcessor.from_pretrained(self.encoder_ckpt)
58
+
59
+ # Create the encoder with proper configuration - use from_pretrained directly
60
+ self.feature_encoder = ImageEncoder.from_pretrained(self.encoder_ckpt).to(self.device)
61
+
62
+ # Setup image transforms for feature extraction
63
+ self.transform = v2.Compose([
64
+ v2.Resize((self.encoder_config.image_size, self.encoder_config.image_size)),
65
+ v2.ToTensor(),
66
+ v2.Normalize(mean=self.encoder_image_processor.image_mean, std=self.encoder_image_processor.image_std),
67
+ ])
68
+ print("Fashion feature extractor model loaded successfully")
69
+ except Exception as e:
70
+ print(f"Error loading fashion feature extractor: {e}")
71
+ self.feature_encoder = None
72
+ self.transform = None
73
+
74
+ # Initialize basic image captioning as fallback
75
+ try:
76
+ self.image_to_text = pipeline(
77
+ "image-to-text",
78
+ model="Salesforce/blip-image-captioning-base",
79
+ device=0 if torch.cuda.is_available() else -1
80
+ )
81
+ print("Basic image captioning model loaded successfully")
82
+ except Exception as e:
83
+ print(f"Error loading image captioning model: {e}")
84
+ self.image_to_text = None
85
+
86
+ # Fashion categories mapping
87
+ self.fashion_categories = {
88
+ 0: 'bag', 1: 'bottom', 2: 'dress', 3: 'hat', 4: 'shoes', 5: 'outer', 6: 'top'
89
+ }
90
+
91
+ def process_image_from_bytes(self, image_bytes):
92
+ """Process image bytes and return PIL Image"""
93
  image = Image.open(io.BytesIO(image_bytes))
94
+
95
  # Convert to RGB if necessary
96
  if image.mode != 'RGB':
97
  image = image.convert('RGB')
98
+
99
+ return image
100
+
 
 
 
 
 
101
  def analyze_clothing_from_bytes(self, image_bytes):
102
+ """Advanced fashion analysis using yainage90 specialized models"""
103
+
104
+ try:
105
+ # Process image
106
+ image = self.process_image_from_bytes(image_bytes)
107
+
108
+ # Get fashion object detection results
109
+ detection_results = self.detect_fashion_objects(image)
110
+
111
+ # Extract fashion features
112
+ fashion_features = self.extract_fashion_features(image)
113
+
114
+ # Get basic image description as fallback
115
+ basic_description = self.get_basic_description(image)
116
+
117
+ # Create comprehensive fashion analysis
118
+ analysis = self.create_advanced_fashion_analysis(detection_results, fashion_features, basic_description, image)
119
+
120
+ return analysis
121
+
122
+ except Exception as e:
123
+ return f"Error analyzing image: {str(e)}"
124
+
125
+ def detect_fashion_objects(self, image):
126
+ """Detect fashion objects using yainage90 fashion detection model"""
127
+ if self.detection_model is None or self.detection_processor is None:
128
+ return {"error": "Fashion detection model not available"}
129
+
130
+ try:
131
+ with torch.no_grad():
132
+ inputs = self.detection_processor(images=[image], return_tensors="pt")
133
+ outputs = self.detection_model(**inputs.to(self.device))
134
+ target_sizes = torch.tensor([[image.size[1], image.size[0]]])
135
+ results = self.detection_processor.post_process_object_detection(
136
+ outputs, threshold=0.4, target_sizes=target_sizes
137
+ )[0]
138
+
139
+ detected_items = []
140
+ for score, label, box in zip(results["scores"], results["labels"], results["boxes"]):
141
+ score = score.item()
142
+ label = label.item()
143
+ box = [i.item() for i in box]
144
+ category = self.detection_model.config.id2label[label]
145
+ detected_items.append({
146
+ 'category': category,
147
+ 'confidence': round(score, 3),
148
+ 'bbox': box
149
+ })
150
+
151
+ return {"detected_items": detected_items}
152
+ except Exception as e:
153
+ return {"error": f"Detection failed: {str(e)}"}
154
+
155
+ def extract_fashion_features(self, image):
156
+ """Extract fashion features using yainage90 feature extractor"""
157
+ if self.feature_encoder is None or self.transform is None:
158
+ return {"error": "Feature extractor not available"}
159
+
160
+ try:
161
+ # Transform image for feature extraction
162
+ image_tensor = self.transform(image)
163
+
164
+ with torch.no_grad():
165
+ embedding = self.feature_encoder(image_tensor.unsqueeze(0).to(self.device))
166
+
167
+ return {
168
+ "feature_vector": embedding.cpu().numpy().tolist(),
169
+ "feature_dimension": embedding.shape[1]
170
  }
171
+ except Exception as e:
172
+ return {"error": f"Feature extraction failed: {str(e)}"}
173
+
174
+ def get_basic_description(self, image):
175
+ """Get basic image description as fallback"""
176
+ if self.image_to_text is None:
177
+ return "Image analysis not available"
178
+
179
  try:
180
+ result = self.image_to_text(image)
181
+ # Convert result to list if it's a generator/iterator
182
+ if result is not None and hasattr(result, '__iter__') and not isinstance(result, (str, bytes)):
183
+ result_list = list(result)
184
+ if result_list and len(result_list) > 0:
185
+ first_result = result_list[0]
186
+ if isinstance(first_result, dict):
187
+ return first_result.get('generated_text', 'Unable to describe image')
188
+ return "Unable to describe image"
189
+ except Exception as e:
190
+ return f"Description failed: {str(e)}"
191
+
192
+ def create_advanced_fashion_analysis(self, detection_results, fashion_features, basic_description, image):
193
+ """Create comprehensive fashion analysis using yainage90 model results"""
194
+
195
+ # Process detection results
196
+ detected_items = detection_results.get('detected_items', [])
197
+ detection_summary = self.summarize_detections(detected_items)
198
+
199
+ # Create comprehensive analysis
200
+ analysis_template = f"""🎽 ADVANCED FASHION ANALYSIS REPORT
201
+
202
+ πŸ” AI-POWERED OBJECT DETECTION:
203
+ {detection_summary}
204
+
205
+ πŸ“‹ DETAILED GARMENT ANALYSIS:
206
+ {self.create_detailed_garment_analysis(detected_items, basic_description)}
207
+
208
+ 🎨 STYLE & DESIGN ASSESSMENT:
209
+ {self.create_style_assessment(detected_items, basic_description)}
210
+
211
+ πŸ’‘ PROFESSIONAL STYLING RECOMMENDATIONS:
212
+ {self.generate_styling_recommendations(detected_items)}
213
+
214
+ πŸ”„ WARDROBE INTEGRATION ADVICE:
215
+ {self.generate_wardrobe_advice(detected_items)}
216
+
217
+ πŸ“Š FASHION SUMMARY:
218
+ {self.create_fashion_summary(detected_items, basic_description)}
219
+
220
+ πŸ€– TECHNICAL DETAILS:
221
+ β€’ Feature Vector Dimension: {fashion_features.get('feature_dimension', 'N/A')}
222
+ β€’ Detection Confidence: {self.get_average_confidence(detected_items)}
223
+ β€’ Analysis Method: yainage90 Fashion AI Models"""
224
+
225
+ return analysis_template
226
+
227
+ def summarize_detections(self, detected_items):
228
+ """Summarize detected fashion items"""
229
+ if not detected_items:
230
+ return "No specific fashion items detected. Using general image analysis."
231
+
232
+ summary_lines = []
233
+ for item in detected_items:
234
+ category = item['category'].upper()
235
+ confidence = item['confidence']
236
+ summary_lines.append(f"β€’ {category}: {confidence*100:.1f}% confidence")
237
+
238
+ return "\n".join(summary_lines)
239
+
240
+ def create_detailed_garment_analysis(self, detected_items, basic_description):
241
+ """Create detailed analysis of detected garments"""
242
+ if not detected_items:
243
+ return f"Based on image analysis: {basic_description}\n" + self.extract_comprehensive_details(basic_description)
244
+
245
+ analysis_parts = []
246
+ for item in detected_items:
247
+ category = item['category']
248
+ confidence = item['confidence']
249
+
250
+ if confidence > 0.5: # High confidence detections
251
+ analysis_parts.append(f"**{category.upper()}** (Confidence: {confidence*100:.1f}%)")
252
+ analysis_parts.append(self.get_category_specific_analysis(category, basic_description))
253
+ analysis_parts.append("") # Add spacing
254
+
255
+ return "\n".join(analysis_parts)
256
+
257
+ def get_category_specific_analysis(self, category, description):
258
+ """Get specific analysis based on detected category"""
259
+ category_analyses = {
260
+ 'top': self.analyze_top_garment(description),
261
+ 'bottom': self.analyze_bottom_garment(description),
262
+ 'dress': self.analyze_dress_garment(description),
263
+ 'outer': self.analyze_outer_garment(description),
264
+ 'shoes': self.analyze_shoes(description),
265
+ 'bag': self.analyze_bag(description),
266
+ 'hat': self.analyze_hat(description)
267
+ }
268
+
269
+ return category_analyses.get(category, f"General {category} analysis based on visual features.")
270
+
271
+ def analyze_top_garment(self, description):
272
+ """Analyze top garments (shirts, blouses, t-shirts)"""
273
+ analysis = []
274
+ desc_lower = description.lower()
275
+
276
+ # Determine specific type
277
+ if 't-shirt' in desc_lower or 'tee' in desc_lower:
278
+ analysis.append("β€’ Type: T-shirt - casual wardrobe staple")
279
+ analysis.append("β€’ Styling: Perfect for layering, casual wear, and relaxed occasions")
280
+ elif 'shirt' in desc_lower or 'blouse' in desc_lower:
281
+ analysis.append("β€’ Type: Shirt/Blouse - versatile professional piece")
282
+ analysis.append("β€’ Styling: Suitable for business casual, can be dressed up or down")
283
+ else:
284
+ analysis.append("β€’ Type: Top garment - versatile upper body wear")
285
+
286
+ # Color analysis
287
+ colors = self.extract_colors(description)
288
+ analysis.append(f"β€’ Color Profile: {colors}")
289
+
290
+ # Fit and style
291
+ fit = self.extract_fit(description)
292
+ analysis.append(f"β€’ Fit & Silhouette: {fit}")
293
+
294
+ # Styling suggestions
295
+ analysis.append("β€’ Styling Tips: Tuck into high-waisted bottoms, layer under jackets, or wear loose for casual looks")
296
+
297
+ return "\n".join(analysis)
298
+
299
+ def analyze_bottom_garment(self, description):
300
+ """Analyze bottom garments (pants, jeans, skirts)"""
301
+ analysis = []
302
+ desc_lower = description.lower()
303
+
304
+ if 'jeans' in desc_lower:
305
+ analysis.append("β€’ Type: Jeans - denim casual essential")
306
+ analysis.append("β€’ Material: Denim fabric, durable and versatile")
307
+ elif 'pants' in desc_lower or 'trousers' in desc_lower:
308
+ analysis.append("β€’ Type: Pants/Trousers - structured bottom wear")
309
+ analysis.append("β€’ Occasion: Professional, semi-formal, or smart casual")
310
+ elif 'skirt' in desc_lower:
311
+ analysis.append("β€’ Type: Skirt - feminine silhouette piece")
312
+ analysis.append("β€’ Style: Adds elegance and movement to outfits")
313
+ else:
314
+ analysis.append("β€’ Type: Bottom garment - lower body wear")
315
+
316
+ fit = self.extract_fit(description)
317
+ analysis.append(f"β€’ Fit & Cut: {fit}")
318
+
319
+ analysis.append("β€’ Styling: Pair with fitted tops for balanced proportions")
320
+
321
+ return "\n".join(analysis)
322
+
323
+ def analyze_dress_garment(self, description):
324
+ """Analyze dress garments"""
325
+ analysis = []
326
+
327
+ analysis.append("β€’ Type: Dress - complete outfit piece")
328
+ analysis.append("β€’ Advantage: Single garment solution for put-together looks")
329
+
330
+ pattern = self.extract_pattern(description)
331
+ analysis.append(f"β€’ Pattern & Design: {pattern}")
332
+
333
+ style = self.extract_style(description)
334
+ analysis.append(f"β€’ Style Category: {style}")
335
+
336
+ occasion = self.extract_occasion(description)
337
+ analysis.append(f"β€’ Best For: {occasion}")
338
+
339
+ analysis.append("β€’ Styling: Add layers, accessories, or shoes to change the look's formality")
340
+
341
+ return "\n".join(analysis)
342
+
343
+ def analyze_outer_garment(self, description):
344
+ """Analyze outer garments (jackets, coats, blazers)"""
345
+ analysis = []
346
+ desc_lower = description.lower()
347
+
348
+ if 'blazer' in desc_lower:
349
+ analysis.append("β€’ Type: Blazer - structured professional outerwear")
350
+ analysis.append("β€’ Function: Adds polish and authority to outfits")
351
+ elif 'jacket' in desc_lower:
352
+ analysis.append("β€’ Type: Jacket - versatile layering piece")
353
+ analysis.append("β€’ Function: Provides warmth and style enhancement")
354
+ elif 'coat' in desc_lower:
355
+ analysis.append("β€’ Type: Coat - substantial outerwear")
356
+ analysis.append("β€’ Function: Weather protection with style")
357
+ else:
358
+ analysis.append("β€’ Type: Outer garment - layering piece")
359
+
360
+ analysis.append("β€’ Styling: Layer over various outfits to change formality level")
361
+ analysis.append("β€’ Versatility: Essential for transitional weather and professional looks")
362
+
363
+ return "\n".join(analysis)
364
+
365
+ def analyze_shoes(self, description):
366
+ """Analyze footwear"""
367
+ analysis = []
368
+ analysis.append("β€’ Type: Footwear - outfit foundation piece")
369
+ analysis.append("β€’ Impact: Significantly influences overall look formality and style")
370
+ analysis.append("β€’ Styling: Choose based on occasion, comfort needs, and outfit balance")
371
+ analysis.append("β€’ Tip: Quality footwear elevates any outfit")
372
+
373
+ return "\n".join(analysis)
374
+
375
+ def analyze_bag(self, description):
376
+ """Analyze bags and accessories"""
377
+ analysis = []
378
+ analysis.append("β€’ Type: Bag/Accessory - functional style element")
379
+ analysis.append("β€’ Purpose: Combines practicality with fashion statement")
380
+ analysis.append("β€’ Styling: Should complement outfit colors and formality level")
381
+ analysis.append("β€’ Tip: Quality bags are investment pieces that enhance multiple outfits")
382
+
383
+ return "\n".join(analysis)
384
+
385
+ def analyze_hat(self, description):
386
+ """Analyze hats and headwear"""
387
+ analysis = []
388
+ analysis.append("β€’ Type: Hat/Headwear - statement accessory")
389
+ analysis.append("β€’ Function: Adds personality and can change outfit's entire vibe")
390
+ analysis.append("β€’ Styling: Consider face shape, hair style, and occasion")
391
+ analysis.append("β€’ Tip: Hats can make simple outfits more interesting and unique")
392
+
393
+ return "\n".join(analysis)
394
+
395
+ def create_style_assessment(self, detected_items, basic_description):
396
+ """Create style assessment based on detected items"""
397
+ if not detected_items:
398
+ return self.extract_style(basic_description)
399
+
400
+ style_elements = []
401
+ categories = [item['category'] for item in detected_items if item['confidence'] > 0.5]
402
+
403
+ if 'dress' in categories:
404
+ style_elements.append("β€’ Feminine and elegant aesthetic")
405
+ style_elements.append("β€’ Single-piece sophistication")
406
+
407
+ if 'blazer' in categories or 'outer' in categories:
408
+ style_elements.append("β€’ Professional and structured elements")
409
+ style_elements.append("β€’ Layered sophistication")
410
+
411
+ if 'jeans' in basic_description.lower() or 'bottom' in categories:
412
+ style_elements.append("β€’ Casual and approachable foundation")
413
+ style_elements.append("β€’ Versatile everyday appeal")
414
+
415
+ if not style_elements:
416
+ style_elements.append("β€’ Contemporary fashion sensibility")
417
+ style_elements.append("β€’ Versatile styling potential")
418
+
419
+ return "\n".join(style_elements)
420
+
421
+ def generate_styling_recommendations(self, detected_items):
422
+ """Generate styling recommendations based on detected items"""
423
+ if not detected_items:
424
+ return "β€’ Focus on fit, color coordination, and occasion appropriateness\nβ€’ Layer pieces to create visual interest\nβ€’ Accessorize to personalize the look"
425
+
426
+ recommendations = []
427
+ categories = [item['category'] for item in detected_items if item['confidence'] > 0.5]
428
+
429
+ if 'top' in categories:
430
+ recommendations.append("β€’ Tuck into high-waisted bottoms for a polished silhouette")
431
+ recommendations.append("β€’ Layer under jackets or cardigans for depth")
432
+
433
+ if 'bottom' in categories:
434
+ recommendations.append("β€’ Pair with fitted tops to balance proportions")
435
+ recommendations.append("β€’ Choose shoes that complement the formality level")
436
+
437
+ if 'dress' in categories:
438
+ recommendations.append("β€’ Add a belt to define the waist")
439
+ recommendations.append("β€’ Layer with jackets or cardigans for versatility")
440
+ recommendations.append("β€’ Change accessories to shift from day to night")
441
+
442
+ if 'outer' in categories:
443
+ recommendations.append("β€’ Use as a statement piece over simple outfits")
444
+ recommendations.append("β€’ Ensure proper fit in shoulders and sleeves")
445
+
446
+ if not recommendations:
447
+ recommendations.append("β€’ Focus on color harmony and proportion balance")
448
+ recommendations.append("β€’ Consider the occasion and dress code")
449
+
450
+ return "\n".join(recommendations)
451
+
452
+ def generate_wardrobe_advice(self, detected_items):
453
+ """Generate wardrobe integration advice"""
454
+ if not detected_items:
455
+ return "β€’ Invest in versatile, quality basics\nβ€’ Build around neutral colors\nβ€’ Choose pieces that work for multiple occasions"
456
+
457
+ advice = []
458
+ categories = [item['category'] for item in detected_items if item['confidence'] > 0.5]
459
+
460
+ if 'top' in categories:
461
+ advice.append("β€’ Essential wardrobe building block")
462
+ advice.append("β€’ Pairs well with multiple bottom styles")
463
+
464
+ if 'bottom' in categories:
465
+ advice.append("β€’ Foundation piece for outfit construction")
466
+ advice.append("β€’ Invest in quality fit and classic styles")
467
+
468
+ if 'dress' in categories:
469
+ advice.append("β€’ Versatile one-piece solution")
470
+ advice.append("β€’ Can be styled for multiple occasions")
471
+
472
+ if 'outer' in categories:
473
+ advice.append("β€’ Transforms and elevates basic outfits")
474
+ advice.append("β€’ Essential for professional wardrobes")
475
+
476
+ advice.append("β€’ Consider cost-per-wear when building wardrobe")
477
+ advice.append("β€’ Focus on pieces that reflect your lifestyle needs")
478
+
479
+ return "\n".join(advice)
480
+
481
+ def create_fashion_summary(self, detected_items, basic_description):
482
+ """Create comprehensive fashion summary"""
483
+ if not detected_items:
484
+ return f"This garment demonstrates contemporary design with versatile styling potential. {basic_description}"
485
+
486
+ primary_items = [item for item in detected_items if item['confidence'] > 0.6]
487
+
488
+ if primary_items:
489
+ main_category = primary_items[0]['category']
490
+ confidence = primary_items[0]['confidence']
491
+
492
+ summary = f"This {main_category} demonstrates {confidence*100:.0f}% detection confidence with professional fashion AI analysis. "
493
+
494
+ if main_category in ['dress']:
495
+ summary += "Offers complete outfit solution with feminine appeal and versatile styling options."
496
+ elif main_category in ['top', 'shirt', 'blouse']:
497
+ summary += "Serves as essential wardrobe foundation with excellent layering and styling flexibility."
498
+ elif main_category in ['bottom', 'pants', 'jeans']:
499
+ summary += "Provides structural foundation for balanced outfit proportions and professional styling."
500
+ elif main_category in ['outer', 'jacket', 'blazer']:
501
+ summary += "Functions as transformative layering piece that elevates casual outfits to professional standards."
502
+ else:
503
+ summary += "Represents quality fashion piece with contemporary appeal and styling versatility."
504
+ else:
505
+ summary = "Fashion analysis indicates contemporary styling with good versatility potential."
506
+
507
+ return summary
508
+
509
+ def get_average_confidence(self, detected_items):
510
+ """Calculate average detection confidence"""
511
+ if not detected_items:
512
+ return "N/A"
513
+
514
+ confidences = [item['confidence'] for item in detected_items]
515
+ avg_confidence = sum(confidences) / len(confidences)
516
+ return f"{avg_confidence*100:.1f}%"
517
+
518
+ def extract_comprehensive_details(self, description):
519
+ """Extract comprehensive details from description"""
520
+ details = []
521
+ details.append(f"β€’ Garment Type: {self.extract_garment_type(description)}")
522
+ details.append(f"β€’ Color Analysis: {self.extract_colors(description)}")
523
+ details.append(f"β€’ Pattern & Design: {self.extract_pattern(description)}")
524
+ details.append(f"β€’ Style Category: {self.extract_style(description)}")
525
+ details.append(f"β€’ Occasion Suitability: {self.extract_occasion(description)}")
526
+
527
+ return "\n".join(details)
528
+
529
+ def clean_generated_text(self, text):
530
+ """Clean and format generated text for better readability"""
531
+ if not text:
532
+ return ""
533
+
534
+ # Remove common artifacts and improve formatting
535
+ text = text.strip()
536
+
537
+ # Remove repetitive phrases
538
+ lines = text.split('\n')
539
+ cleaned_lines = []
540
+ seen_lines = set()
541
+
542
+ for line in lines:
543
+ line = line.strip()
544
+ if line and line not in seen_lines and len(line) > 10:
545
+ cleaned_lines.append(line)
546
+ seen_lines.add(line)
547
+
548
+ return '\n'.join(cleaned_lines[:5]) # Limit to 5 unique lines
549
+
550
+ def generate_advanced_insights(self, description):
551
+ """Generate sophisticated fashion insights when AI generation fails"""
552
+ garment_type = self.extract_garment_type(description).lower()
553
+ colors = self.extract_colors(description).lower()
554
+ pattern = self.extract_pattern(description).lower()
555
+ style = self.extract_style(description).lower()
556
+
557
+ insights = []
558
+
559
+ # Advanced garment-specific insights
560
+ if 'dress' in garment_type:
561
+ if 'floral' in pattern:
562
+ insights.extend([
563
+ "This floral dress exemplifies the timeless appeal of botanical motifs in women's fashion.",
564
+ "The floral pattern creates visual movement and adds romantic femininity to the silhouette.",
565
+ "Ideal for transitional seasons and outdoor social events where natural beauty is celebrated."
566
+ ])
567
+ elif 'black' in colors:
568
+ insights.extend([
569
+ "The classic black dress represents the epitome of versatile elegance in fashion.",
570
+ "This piece serves as a foundational wardrobe element with endless styling possibilities.",
571
+ "Perfect for day-to-night transitions with simple accessory changes."
572
+ ])
573
+ else:
574
+ insights.extend([
575
+ "This dress demonstrates contemporary design principles with classic appeal.",
576
+ "The silhouette offers both comfort and sophisticated style for modern lifestyles."
577
+ ])
578
+ elif any(item in garment_type for item in ['shirt', 'blouse', 'top']):
579
+ insights.extend([
580
+ "This top represents a versatile foundation piece essential for capsule wardrobes.",
581
+ "The design allows for multiple styling interpretations from casual to professional.",
582
+ "Perfect for layering strategies and seasonal wardrobe transitions."
583
+ ])
584
+ elif any(item in garment_type for item in ['pants', 'jeans', 'trousers']):
585
+ insights.extend([
586
+ "These bottoms provide structural foundation for balanced outfit proportions.",
587
+ "The cut and fit demonstrate attention to contemporary silhouette preferences.",
588
+ "Suitable for building cohesive looks across casual and semi-formal contexts."
589
+ ])
590
+
591
+ # Add sophisticated pattern and color insights
592
+ if 'floral' in pattern:
593
+ insights.append("The botanical motif connects the wearer to nature-inspired fashion trends and seasonal styling.")
594
+ elif 'solid' in pattern:
595
+ insights.append("The solid construction maximizes styling versatility and accessory compatibility.")
596
+ elif 'striped' in pattern:
597
+ insights.append("The linear pattern creates visual interest while maintaining classic appeal.")
598
+
599
+ # Add color psychology insights
600
+ if 'black' in colors:
601
+ insights.append("Black conveys sophistication, authority, and timeless elegance in fashion psychology.")
602
+ elif 'white' in colors:
603
+ insights.append("White represents purity, freshness, and minimalist aesthetic principles.")
604
+ elif any(color in colors for color in ['blue', 'navy']):
605
+ insights.append("Blue tones suggest reliability, professionalism, and calming visual impact.")
606
+ elif any(color in colors for color in ['red', 'burgundy']):
607
+ insights.append("Red spectrum colors project confidence, energy, and bold fashion statements.")
608
+
609
+ return ' '.join(insights) if insights else "This garment demonstrates thoughtful design principles with contemporary market appeal and versatile styling potential."
610
+
611
+ def generate_fallback_insights(self, description):
612
+ """Generate fallback insights when AI text generation fails"""
613
+ garment_type = self.extract_garment_type(description).lower()
614
+ pattern = self.extract_pattern(description).lower()
615
+
616
+ insights = []
617
+
618
+ if 'dress' in garment_type:
619
+ if 'floral' in pattern:
620
+ insights.extend([
621
+ "This floral dress embodies feminine elegance and seasonal charm.",
622
+ "The floral pattern adds visual interest and romantic appeal.",
623
+ "Perfect for spring/summer occasions and outdoor events."
624
+ ])
625
+ else:
626
+ insights.extend([
627
+ "This dress offers versatile styling options for various occasions.",
628
+ "The silhouette provides both comfort and style."
629
+ ])
630
+ elif any(item in garment_type for item in ['shirt', 'blouse']):
631
+ insights.extend([
632
+ "This top serves as a versatile wardrobe foundation piece.",
633
+ "Can be styled up or down depending on the occasion."
634
+ ])
635
+ elif any(item in garment_type for item in ['pants', 'jeans']):
636
+ insights.extend([
637
+ "These bottoms provide a solid foundation for outfit building.",
638
+ "Suitable for both casual and semi-formal styling."
639
+ ])
640
+
641
+ # Add pattern-specific insights
642
+ if 'floral' in pattern:
643
+ insights.append("The floral motif brings natural beauty and femininity to the design.")
644
+ elif 'solid' in pattern:
645
+ insights.append("The solid color provides versatility for accessorizing and layering.")
646
+
647
+ return ' '.join(insights) if insights else "This garment demonstrates classic design principles with contemporary appeal."
648
+
649
+ def extract_garment_type(self, description):
650
+ """Extract garment type from description with enhanced detection"""
651
+ garment_keywords = {
652
+ 'dress': 'Dress',
653
+ 'gown': 'Evening Gown',
654
+ 'shirt': 'Shirt/Blouse',
655
+ 'blouse': 'Blouse',
656
+ 'top': 'Top',
657
+ 't-shirt': 'T-Shirt',
658
+ 'tank': 'Tank Top',
659
+ 'camisole': 'Camisole',
660
+ 'pants': 'Pants/Trousers',
661
+ 'trousers': 'Trousers',
662
+ 'jeans': 'Jeans',
663
+ 'leggings': 'Leggings',
664
+ 'jacket': 'Jacket',
665
+ 'blazer': 'Blazer',
666
+ 'coat': 'Coat',
667
+ 'cardigan': 'Cardigan',
668
+ 'sweater': 'Sweater',
669
+ 'pullover': 'Pullover',
670
+ 'hoodie': 'Hoodie',
671
+ 'sweatshirt': 'Sweatshirt',
672
+ 'skirt': 'Skirt',
673
+ 'shorts': 'Shorts',
674
+ 'jumpsuit': 'Jumpsuit',
675
+ 'romper': 'Romper',
676
+ 'vest': 'Vest',
677
+ 'tunic': 'Tunic'
678
+ }
679
+
680
+ description_lower = description.lower()
681
+
682
+ # Check for specific garment types first
683
+ for keyword, garment_type in garment_keywords.items():
684
+ if keyword in description_lower:
685
+ return garment_type
686
+
687
+ # Fallback analysis based on context clues
688
+ if any(word in description_lower for word in ['wearing', 'outfit', 'clothing']):
689
+ return "Fashion Garment"
690
+
691
+ return "Clothing Item"
692
+
693
+ def extract_colors(self, description):
694
+ """Extract colors from description with enhanced detection and color theory analysis"""
695
+ color_keywords = {
696
+ 'black': {'name': 'Black', 'category': 'neutral', 'season': 'all', 'formality': 'high'},
697
+ 'white': {'name': 'White', 'category': 'neutral', 'season': 'all', 'formality': 'high'},
698
+ 'blue': {'name': 'Blue', 'category': 'cool', 'season': 'all', 'formality': 'medium'},
699
+ 'navy': {'name': 'Navy Blue', 'category': 'neutral', 'season': 'all', 'formality': 'high'},
700
+ 'red': {'name': 'Red', 'category': 'warm', 'season': 'winter', 'formality': 'medium'},
701
+ 'green': {'name': 'Green', 'category': 'cool', 'season': 'spring', 'formality': 'medium'},
702
+ 'yellow': {'name': 'Yellow', 'category': 'warm', 'season': 'summer', 'formality': 'low'},
703
+ 'pink': {'name': 'Pink', 'category': 'warm', 'season': 'spring', 'formality': 'low'},
704
+ 'purple': {'name': 'Purple', 'category': 'cool', 'season': 'fall', 'formality': 'medium'},
705
+ 'brown': {'name': 'Brown', 'category': 'neutral', 'season': 'fall', 'formality': 'medium'},
706
+ 'gray': {'name': 'Gray', 'category': 'neutral', 'season': 'all', 'formality': 'high'},
707
+ 'grey': {'name': 'Gray', 'category': 'neutral', 'season': 'all', 'formality': 'high'},
708
+ 'orange': {'name': 'Orange', 'category': 'warm', 'season': 'fall', 'formality': 'low'},
709
+ 'beige': {'name': 'Beige', 'category': 'neutral', 'season': 'all', 'formality': 'medium'},
710
+ 'cream': {'name': 'Cream', 'category': 'neutral', 'season': 'spring', 'formality': 'medium'},
711
+ 'tan': {'name': 'Tan', 'category': 'neutral', 'season': 'summer', 'formality': 'medium'},
712
+ 'gold': {'name': 'Gold', 'category': 'warm', 'season': 'fall', 'formality': 'high'},
713
+ 'silver': {'name': 'Silver', 'category': 'cool', 'season': 'winter', 'formality': 'high'},
714
+ 'maroon': {'name': 'Maroon', 'category': 'warm', 'season': 'fall', 'formality': 'high'},
715
+ 'burgundy': {'name': 'Burgundy', 'category': 'warm', 'season': 'fall', 'formality': 'high'},
716
+ 'teal': {'name': 'Teal', 'category': 'cool', 'season': 'winter', 'formality': 'medium'},
717
+ 'turquoise': {'name': 'Turquoise', 'category': 'cool', 'season': 'summer', 'formality': 'low'},
718
+ 'coral': {'name': 'Coral', 'category': 'warm', 'season': 'summer', 'formality': 'low'},
719
+ 'mint': {'name': 'Mint', 'category': 'cool', 'season': 'spring', 'formality': 'low'},
720
+ 'lavender': {'name': 'Lavender', 'category': 'cool', 'season': 'spring', 'formality': 'low'}
721
+ }
722
+
723
+ description_lower = description.lower()
724
+ found_colors = []
725
+
726
+ for keyword, color_info in color_keywords.items():
727
+ if keyword in description_lower:
728
+ if color_info not in found_colors: # Avoid duplicates
729
+ found_colors.append(color_info)
730
+
731
+ if found_colors:
732
+ primary_color = found_colors[0]
733
+ color_analysis = []
734
+
735
+ # Primary color analysis
736
+ color_analysis.append(f"Primary: {primary_color['name']}")
737
+
738
+ # Color theory insights
739
+ if primary_color['category'] == 'neutral':
740
+ color_analysis.append("(Neutral - highly versatile)")
741
+ elif primary_color['category'] == 'warm':
742
+ color_analysis.append("(Warm tone - energetic and approachable)")
743
+ else:
744
+ color_analysis.append("(Cool tone - calming and professional)")
745
+
746
+ # Seasonal and styling context
747
+ if primary_color['season'] != 'all':
748
+ color_analysis.append(f"Best for {primary_color['season']} styling")
749
+
750
+ # Formality level
751
+ if primary_color['formality'] == 'high':
752
+ color_analysis.append("Suitable for formal occasions")
753
+ elif primary_color['formality'] == 'medium':
754
+ color_analysis.append("Versatile for casual to semi-formal")
755
+ else:
756
+ color_analysis.append("Perfect for casual, relaxed styling")
757
+
758
+ # Additional colors
759
+ if len(found_colors) > 1:
760
+ other_colors = [c['name'] for c in found_colors[1:]]
761
+ color_analysis.append(f"Secondary: {', '.join(other_colors)}")
762
+
763
+ return ' β€’ '.join(color_analysis)
764
+ else:
765
+ # Try to infer from context
766
+ if any(word in description_lower for word in ['dark', 'deep']):
767
+ return "Dark tones detected β€’ Creates sophisticated, slimming effect β€’ Suitable for formal occasions"
768
+ elif any(word in description_lower for word in ['light', 'pale', 'bright']):
769
+ return "Light/bright tones detected β€’ Fresh, youthful appearance β€’ Perfect for casual, daytime wear"
770
+ else:
771
+ return "Mixed color palette β€’ Offers styling versatility β€’ Consider color coordination principles"
772
+
773
+ def extract_neckline(self, description):
774
+ """Extract neckline information with intelligent inference"""
775
+ description_lower = description.lower()
776
+
777
+ # Direct detection
778
+ neckline_keywords = {
779
+ 'v-neck': 'V-neckline',
780
+ 'scoop': 'Scoop neckline',
781
+ 'crew': 'Crew neckline',
782
+ 'round': 'Round neckline',
783
+ 'collar': 'Collared',
784
+ 'turtleneck': 'Turtleneck',
785
+ 'off-shoulder': 'Off-shoulder',
786
+ 'strapless': 'Strapless',
787
+ 'halter': 'Halter neckline'
788
+ }
789
+
790
+ for keyword, neckline_type in neckline_keywords.items():
791
+ if keyword in description_lower:
792
+ return neckline_type
793
+
794
+ # Intelligent inference based on garment type
795
+ if 'dress' in description_lower:
796
+ if 'formal' in description_lower or 'evening' in description_lower:
797
+ return "Likely elegant neckline (common for dresses)"
798
+ else:
799
+ return "Standard dress neckline (round or scoop typical)"
800
+ elif any(word in description_lower for word in ['shirt', 'blouse']):
801
+ return "Standard shirt collar or neckline"
802
+ elif 't-shirt' in description_lower:
803
+ return "Crew or round neckline (typical for t-shirts)"
804
+
805
+ return "Neckline present but style not specified"
806
+
807
+ def extract_sleeves(self, description):
808
+ """Extract sleeve information with intelligent inference"""
809
+ description_lower = description.lower()
810
+
811
+ # Direct detection
812
+ sleeve_keywords = {
813
+ 'long sleeve': 'Long sleeves',
814
+ 'short sleeve': 'Short sleeves',
815
+ 'sleeveless': 'Sleeveless',
816
+ 'cap sleeve': 'Cap sleeves',
817
+ 'three-quarter': '3/4 sleeves',
818
+ 'bell sleeve': 'Bell sleeves',
819
+ 'puff sleeve': 'Puff sleeves'
820
+ }
821
+
822
+ for keyword, sleeve_type in sleeve_keywords.items():
823
+ if keyword in description_lower:
824
+ return sleeve_type
825
+
826
+ # Intelligent inference based on garment type
827
+ if 'dress' in description_lower:
828
+ if 'summer' in description_lower or 'floral' in description_lower:
829
+ return "Likely short sleeves or sleeveless (common for summer/floral dresses)"
830
+ elif 'winter' in description_lower or 'formal' in description_lower:
831
+ return "Likely long sleeves (common for formal/winter dresses)"
832
+ else:
833
+ return "Sleeve style varies (short sleeves, sleeveless, or straps typical for dresses)"
834
+ elif 't-shirt' in description_lower:
835
+ return "Short sleeves (standard for t-shirts)"
836
+ elif any(word in description_lower for word in ['jacket', 'blazer', 'coat']):
837
+ return "Long sleeves (standard for outerwear)"
838
+ elif any(word in description_lower for word in ['tank', 'camisole']):
839
+ return "Sleeveless or thin straps"
840
+
841
+ return "Sleeve style not specified in description"
842
+
843
+ def extract_pattern(self, description):
844
+ """Extract pattern information with enhanced detection"""
845
+ pattern_keywords = {
846
+ 'floral': 'Floral print',
847
+ 'flower': 'Floral design',
848
+ 'striped': 'Striped pattern',
849
+ 'stripes': 'Striped pattern',
850
+ 'plaid': 'Plaid pattern',
851
+ 'checkered': 'Checkered pattern',
852
+ 'polka dot': 'Polka dot pattern',
853
+ 'dots': 'Dotted pattern',
854
+ 'geometric': 'Geometric pattern',
855
+ 'abstract': 'Abstract pattern',
856
+ 'paisley': 'Paisley pattern',
857
+ 'animal print': 'Animal print',
858
+ 'leopard': 'Leopard print',
859
+ 'zebra': 'Zebra print',
860
+ 'solid': 'Solid color',
861
+ 'plain': 'Plain/solid',
862
+ 'printed': 'Printed design',
863
+ 'embroidered': 'Embroidered details',
864
+ 'lace': 'Lace pattern',
865
+ 'textured': 'Textured fabric'
866
+ }
867
+
868
+ description_lower = description.lower()
869
+ found_patterns = []
870
+
871
+ for keyword, pattern_name in pattern_keywords.items():
872
+ if keyword in description_lower:
873
+ if pattern_name not in found_patterns:
874
+ found_patterns.append(pattern_name)
875
+
876
+ if found_patterns:
877
+ return ', '.join(found_patterns)
878
+ else:
879
+ # Try to infer from context
880
+ if any(word in description_lower for word in ['print', 'design', 'pattern']):
881
+ return "Decorative pattern present"
882
+ else:
883
+ return "Solid or minimal pattern"
884
+
885
+ def extract_fit(self, description):
886
+ """Extract fit information with intelligent inference"""
887
+ description_lower = description.lower()
888
+
889
+ # Direct detection
890
+ fit_keywords = {
891
+ 'loose': 'Loose fit',
892
+ 'tight': 'Tight/fitted',
893
+ 'fitted': 'Fitted',
894
+ 'oversized': 'Oversized',
895
+ 'slim': 'Slim fit',
896
+ 'relaxed': 'Relaxed fit',
897
+ 'bodycon': 'Body-conscious fit',
898
+ 'a-line': 'A-line silhouette',
899
+ 'straight': 'Straight fit'
900
+ }
901
+
902
+ for keyword, fit_type in fit_keywords.items():
903
+ if keyword in description_lower:
904
+ return fit_type
905
+
906
+ # Intelligent inference based on garment type and style
907
+ if 'dress' in description_lower:
908
+ if 'floral' in description_lower:
909
+ return "Likely flowing or A-line fit (common for floral dresses)"
910
+ elif 'formal' in description_lower:
911
+ return "Likely fitted or tailored silhouette"
912
+ else:
913
+ return "Dress silhouette (fit varies by style)"
914
+ elif any(word in description_lower for word in ['jeans', 'pants']):
915
+ return "Standard trouser fit (straight, slim, or relaxed)"
916
+ elif any(word in description_lower for word in ['blazer', 'jacket']):
917
+ return "Tailored fit (structured silhouette)"
918
+ elif 't-shirt' in description_lower:
919
+ return "Regular fit (standard t-shirt silhouette)"
920
+
921
+ return "Fit style not specified in description"
922
+
923
+ def extract_material(self, description):
924
+ """Extract material information with intelligent inference"""
925
+ description_lower = description.lower()
926
+
927
+ # Direct detection
928
+ material_keywords = {
929
+ 'cotton': 'Cotton',
930
+ 'denim': 'Denim',
931
+ 'silk': 'Silk',
932
+ 'wool': 'Wool',
933
+ 'polyester': 'Polyester',
934
+ 'leather': 'Leather',
935
+ 'linen': 'Linen',
936
+ 'chiffon': 'Chiffon',
937
+ 'satin': 'Satin',
938
+ 'velvet': 'Velvet',
939
+ 'lace': 'Lace',
940
+ 'knit': 'Knit fabric',
941
+ 'jersey': 'Jersey',
942
+ 'tweed': 'Tweed'
943
+ }
944
+
945
+ found_materials = []
946
+ for keyword, material_name in material_keywords.items():
947
+ if keyword in description_lower:
948
+ found_materials.append(material_name)
949
+
950
+ if found_materials:
951
+ return ', '.join(found_materials)
952
+
953
+ # Intelligent inference based on garment type
954
+ if 'dress' in description_lower:
955
+ if 'floral' in description_lower:
956
+ return "Likely lightweight fabric (cotton, chiffon, or jersey common for floral dresses)"
957
+ elif 'formal' in description_lower:
958
+ return "Likely elegant fabric (silk, satin, or crepe)"
959
+ else:
960
+ return "Dress fabric (varies by style and season)"
961
+ elif 'jeans' in description_lower:
962
+ return "Denim (standard for jeans)"
963
+ elif 't-shirt' in description_lower:
964
+ return "Cotton or cotton blend (typical for t-shirts)"
965
+ elif any(word in description_lower for word in ['blazer', 'suit']):
966
+ return "Structured fabric (wool, polyester blend, or cotton)"
967
+ elif 'sweater' in description_lower:
968
+ return "Knit fabric (wool, cotton, or synthetic blend)"
969
+
970
+ return "Fabric type not specified in description"
971
+
972
+ def extract_features(self, description):
973
+ """Extract features information"""
974
+ feature_keywords = ['button', 'zip', 'pocket', 'belt', 'hood']
975
+ description_lower = description.lower()
976
+ found_features = [feature for feature in feature_keywords if feature in description_lower]
977
+ return ', '.join(found_features).title() if found_features else "Specific features not clearly visible"
978
+
979
+ def extract_style(self, description):
980
+ """Extract style information with intelligent inference"""
981
+ description_lower = description.lower()
982
+
983
+ # Direct detection
984
+ style_keywords = {
985
+ 'casual': 'Casual',
986
+ 'formal': 'Formal',
987
+ 'business': 'Business/Professional',
988
+ 'sporty': 'Sporty/Athletic',
989
+ 'elegant': 'Elegant',
990
+ 'vintage': 'Vintage',
991
+ 'bohemian': 'Bohemian',
992
+ 'minimalist': 'Minimalist',
993
+ 'romantic': 'Romantic',
994
+ 'edgy': 'Edgy',
995
+ 'classic': 'Classic',
996
+ 'trendy': 'Trendy/Contemporary'
997
+ }
998
+
999
+ found_styles = []
1000
+ for keyword, style_name in style_keywords.items():
1001
+ if keyword in description_lower:
1002
+ found_styles.append(style_name)
1003
+
1004
+ if found_styles:
1005
+ return ', '.join(found_styles)
1006
+
1007
+ # Intelligent inference based on garment type and patterns
1008
+ if 'dress' in description_lower:
1009
+ if 'floral' in description_lower:
1010
+ return "Feminine/Romantic (floral dresses often have romantic appeal)"
1011
+ elif 'black' in description_lower:
1012
+ return "Classic/Versatile (black dresses are wardrobe staples)"
1013
+ else:
1014
+ return "Feminine/Versatile (dresses suit various style preferences)"
1015
+ elif any(word in description_lower for word in ['blazer', 'suit']):
1016
+ return "Professional/Business (structured formal wear)"
1017
+ elif 'jeans' in description_lower:
1018
+ return "Casual/Everyday (denim is casual staple)"
1019
+ elif 't-shirt' in description_lower:
1020
+ return "Casual/Relaxed (t-shirts are casual basics)"
1021
+ elif any(word in description_lower for word in ['jacket', 'coat']):
1022
+ return "Outerwear/Functional (practical and stylish)"
1023
+
1024
+ return "Versatile style (suitable for multiple aesthetics)"
1025
+
1026
+ def extract_occasion(self, description):
1027
+ """Extract occasion information"""
1028
+ if any(word in description.lower() for word in ['formal', 'business', 'suit']):
1029
+ return "Formal occasions, business settings"
1030
+ elif any(word in description.lower() for word in ['casual', 'everyday']):
1031
+ return "Casual wear, everyday use"
1032
+ else:
1033
+ return "Versatile for multiple occasions"
1034
+
1035
+ def generate_styling_tips(self, description):
1036
+ """Generate styling tips based on the garment"""
1037
+ garment_type = self.extract_garment_type(description).lower()
1038
+ pattern = self.extract_pattern(description).lower()
1039
+
1040
+ tips = []
1041
+
1042
+ if 'dress' in garment_type:
1043
+ tips.extend([
1044
+ "β€’ Pair with a denim jacket for casual daywear",
1045
+ "β€’ Add heels and accessories for evening events",
1046
+ "β€’ Layer with a cardigan for office-appropriate styling"
1047
+ ])
1048
+ elif 'shirt' in garment_type or 'blouse' in garment_type:
1049
+ tips.extend([
1050
+ "β€’ Tuck into high-waisted pants for a polished look",
1051
+ "β€’ Wear open over a tank top for layered styling",
1052
+ "β€’ Knot at the waist for a casual, trendy appearance"
1053
+ ])
1054
+ elif 'pants' in garment_type or 'jeans' in garment_type:
1055
+ tips.extend([
1056
+ "β€’ Pair with a fitted top to balance proportions",
1057
+ "β€’ Add a blazer for business casual styling",
1058
+ "β€’ Combine with sneakers for comfortable everyday wear"
1059
+ ])
1060
+
1061
+ if 'floral' in pattern:
1062
+ tips.append("β€’ Keep accessories minimal to let the pattern shine")
1063
+ elif 'solid' in pattern:
1064
+ tips.append("β€’ Perfect base for statement accessories and bold jewelry")
1065
+
1066
+ return '\n'.join(tips) if tips else "β€’ Versatile piece suitable for various styling approaches"
1067
+
1068
+ def get_versatility_assessment(self, description):
1069
+ """Assess the versatility of the garment"""
1070
+ garment_type = self.extract_garment_type(description).lower()
1071
+ colors = self.extract_colors(description).lower()
1072
+ pattern = self.extract_pattern(description).lower()
1073
+
1074
+ versatility_score = 0
1075
+ assessment_parts = []
1076
+
1077
+ # Assess based on garment type
1078
+ if any(item in garment_type for item in ['dress', 'shirt', 'blouse', 'pants', 'jeans']):
1079
+ versatility_score += 2
1080
+ assessment_parts.append("highly versatile garment type")
1081
+
1082
+ # Assess based on colors
1083
+ if any(color in colors for color in ['black', 'white', 'navy', 'gray']):
1084
+ versatility_score += 2
1085
+ assessment_parts.append("neutral color palette")
1086
+ elif colors == "colors not clearly identified":
1087
+ versatility_score += 1
1088
+ assessment_parts.append("adaptable color scheme")
1089
+
1090
+ # Assess based on pattern
1091
+ if 'solid' in pattern:
1092
+ versatility_score += 2
1093
+ assessment_parts.append("solid pattern for easy mixing")
1094
+ elif any(p in pattern for p in ['floral', 'striped']):
1095
+ versatility_score += 1
1096
+ assessment_parts.append("distinctive pattern adds character")
1097
+
1098
+ if versatility_score >= 4:
1099
+ return f"This is a {', '.join(assessment_parts)} making it an excellent wardrobe staple."
1100
+ elif versatility_score >= 2:
1101
+ return f"Features {', '.join(assessment_parts)} providing good styling flexibility."
1102
+ else:
1103
+ return "Offers unique styling opportunities for specific occasions."
1104
 
1105
  # Initialize analyzer
1106
+ analyzer = HuggingFaceFashionAnalyzer()
1107
 
1108
  # Request/Response models
1109
  class AnalysisResponse(BaseModel):
 
1191
  async def health_check():
1192
  """Health check endpoint"""
1193
  try:
1194
+ # Test HuggingFace models availability
1195
+ if hasattr(analyzer, 'image_to_text') and analyzer.image_to_text is not None:
1196
+ return {"status": "healthy", "models": "loaded", "device": analyzer.device}
 
1197
  else:
1198
+ return {"status": "unhealthy", "models": "not_loaded"}
1199
+ except Exception as e:
1200
+ return {"status": "unhealthy", "error": str(e)}
1201
 
1202
  if __name__ == "__main__":
1203
+ uvicorn.run(app, host="0.0.0.0", port=7861)
requirements.txt CHANGED
@@ -1,6 +1,56 @@
 
 
 
 
 
 
1
  fastapi==0.104.1
2
- uvicorn==0.24.0
3
- requests==2.31.0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  Pillow==10.0.1
 
5
  pydantic==2.4.2
6
- python-multipart
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ accelerate==1.8.1
2
+ annotated-types==0.7.0
3
+ anyio==3.7.1
4
+ certifi==2025.6.15
5
+ charset-normalizer==3.4.2
6
+ click==8.2.1
7
  fastapi==0.104.1
8
+ filelock==3.18.0
9
+ fsspec==2025.5.1
10
+ h11==0.16.0
11
+ hf-xet==1.1.5
12
+ huggingface-hub==0.33.0
13
+ idna==3.10
14
+ Jinja2==3.1.6
15
+ MarkupSafe==3.0.2
16
+ mpmath==1.3.0
17
+ networkx==3.5
18
+ numpy==2.3.1
19
+ nvidia-cublas-cu12==12.6.4.1
20
+ nvidia-cuda-cupti-cu12==12.6.80
21
+ nvidia-cuda-nvrtc-cu12==12.6.77
22
+ nvidia-cuda-runtime-cu12==12.6.77
23
+ nvidia-cudnn-cu12==9.5.1.17
24
+ nvidia-cufft-cu12==11.3.0.4
25
+ nvidia-cufile-cu12==1.11.1.6
26
+ nvidia-curand-cu12==10.3.7.77
27
+ nvidia-cusolver-cu12==11.7.1.2
28
+ nvidia-cusparse-cu12==12.5.4.2
29
+ nvidia-cusparselt-cu12==0.6.3
30
+ nvidia-nccl-cu12==2.26.2
31
+ nvidia-nvjitlink-cu12==12.6.85
32
+ nvidia-nvtx-cu12==12.6.77
33
+ packaging==25.0
34
  Pillow==10.0.1
35
+ psutil==7.0.0
36
  pydantic==2.4.2
37
+ pydantic_core==2.10.1
38
+ python-multipart==0.0.20
39
+ PyYAML==6.0.2
40
+ regex==2024.11.6
41
+ requests==2.31.0
42
+ safetensors==0.5.3
43
+ setuptools==80.9.0
44
+ sniffio==1.3.1
45
+ starlette==0.27.0
46
+ sympy==1.14.0
47
+ timm==1.0.15
48
+ tokenizers==0.21.1
49
+ torch==2.7.1
50
+ torchvision==0.22.1
51
+ tqdm==4.67.1
52
+ transformers==4.52.4
53
+ triton==3.3.1
54
+ typing_extensions==4.14.0
55
+ urllib3==2.5.0
56
+ uvicorn==0.24.0
test_hf_conversion.py ADDED
@@ -0,0 +1,130 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Test script to verify HuggingFace conversion works
4
+ """
5
+
6
+ import sys
7
+ import os
8
+
9
+ def test_imports():
10
+ """Test if all required imports work"""
11
+ try:
12
+ print("Testing imports...")
13
+
14
+ # Test basic imports
15
+ from PIL import Image
16
+ import io
17
+ print("βœ… PIL and io imports successful")
18
+
19
+ # Test transformers import
20
+ try:
21
+ from transformers import pipeline
22
+ print("βœ… transformers import successful")
23
+ except ImportError as e:
24
+ print(f"❌ transformers import failed: {e}")
25
+ return False
26
+
27
+ # Test torch import
28
+ try:
29
+ import torch
30
+ print(f"βœ… torch import successful (version: {torch.__version__})")
31
+ print(f" CUDA available: {torch.cuda.is_available()}")
32
+ except ImportError as e:
33
+ print(f"❌ torch import failed: {e}")
34
+ return False
35
+
36
+ return True
37
+
38
+ except Exception as e:
39
+ print(f"❌ Import test failed: {e}")
40
+ return False
41
+
42
+ def test_pipeline_creation():
43
+ """Test if we can create the HuggingFace pipeline"""
44
+ try:
45
+ print("\nTesting pipeline creation...")
46
+
47
+ from transformers import pipeline
48
+
49
+ # Try to create image captioning pipeline
50
+ print("Creating image-to-text pipeline...")
51
+ image_to_text = pipeline(
52
+ "image-to-text",
53
+ model="Salesforce/blip-image-captioning-base",
54
+ device=-1 # Force CPU to avoid GPU issues
55
+ )
56
+ print("βœ… Image-to-text pipeline created successfully")
57
+
58
+ return True
59
+
60
+ except Exception as e:
61
+ print(f"❌ Pipeline creation failed: {e}")
62
+ return False
63
+
64
+ def test_basic_functionality():
65
+ """Test basic functionality with a simple image"""
66
+ try:
67
+ print("\nTesting basic functionality...")
68
+
69
+ from transformers import pipeline
70
+ from PIL import Image
71
+ import io
72
+
73
+ # Create a simple test image
74
+ test_image = Image.new('RGB', (100, 100), color='red')
75
+
76
+ # Create pipeline
77
+ image_to_text = pipeline(
78
+ "image-to-text",
79
+ model="Salesforce/blip-image-captioning-base",
80
+ device=-1
81
+ )
82
+
83
+ # Test image captioning
84
+ result = image_to_text(test_image)
85
+ print(f"βœ… Image captioning successful: {result}")
86
+
87
+ return True
88
+
89
+ except Exception as e:
90
+ print(f"❌ Basic functionality test failed: {e}")
91
+ return False
92
+
93
+ def main():
94
+ """Run all tests"""
95
+ print("πŸ§ͺ Testing HuggingFace Fashion Analyzer Conversion")
96
+ print("=" * 50)
97
+
98
+ tests = [
99
+ ("Import Test", test_imports),
100
+ ("Pipeline Creation Test", test_pipeline_creation),
101
+ ("Basic Functionality Test", test_basic_functionality)
102
+ ]
103
+
104
+ passed = 0
105
+ total = len(tests)
106
+
107
+ for test_name, test_func in tests:
108
+ print(f"\nπŸ” Running {test_name}...")
109
+ try:
110
+ if test_func():
111
+ print(f"βœ… {test_name} PASSED")
112
+ passed += 1
113
+ else:
114
+ print(f"❌ {test_name} FAILED")
115
+ except Exception as e:
116
+ print(f"❌ {test_name} FAILED with exception: {e}")
117
+
118
+ print("\n" + "=" * 50)
119
+ print(f"πŸ“Š Test Results: {passed}/{total} tests passed")
120
+
121
+ if passed == total:
122
+ print("πŸŽ‰ All tests passed! HuggingFace conversion is ready.")
123
+ return True
124
+ else:
125
+ print("⚠️ Some tests failed. Check the errors above.")
126
+ return False
127
+
128
+ if __name__ == "__main__":
129
+ success = main()
130
+ sys.exit(0 if success else 1)