Spaces:
Sleeping
Sleeping
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.
- fast.py +1093 -74
- requirements.txt +53 -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="
|
15 |
|
16 |
-
class
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
self.
|
21 |
-
|
22 |
-
|
23 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
-
|
31 |
-
|
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 |
-
"""
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
"
|
65 |
-
|
66 |
-
|
67 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
68 |
}
|
69 |
-
|
70 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
71 |
try:
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
return
|
81 |
-
|
82 |
-
|
83 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
84 |
|
85 |
# Initialize analyzer
|
86 |
-
analyzer =
|
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
|
175 |
-
|
176 |
-
|
177 |
-
return {"status": "healthy", "ollama": "connected"}
|
178 |
else:
|
179 |
-
return {"status": "unhealthy", "
|
180 |
-
except:
|
181 |
-
return {"status": "unhealthy", "
|
182 |
|
183 |
if __name__ == "__main__":
|
184 |
-
uvicorn.run(app, host="0.0.0.0", port=
|
|
|
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 |
-
|
3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
Pillow==10.0.1
|
|
|
5 |
pydantic==2.4.2
|
6 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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)
|