style-analysis / analyzer.py
SudaisKhan211's picture
fix the code
d09ca9f
"""
AI-Powered Style Analyzer using Google Gemini
This module analyzes user-uploaded images for:
- Body type and features
- Body alignment and posture
- Skin tone and undertones
- Face shape
- Style recommendations based on analysis
Uses Google's Gemini AI for comprehensive image analysis.
"""
import os
import io
import base64
from typing import Dict, Any, Optional, Union
from pathlib import Path
from PIL import Image
from dotenv import load_dotenv
import traceback
try:
from google import genai
from google.genai import types
GOOGLE_GENAI_AVAILABLE = True
except ImportError:
GOOGLE_GENAI_AVAILABLE = False
genai = None
types = None
class StyleAnalyzer:
"""
AI-powered style analyzer using Google Gemini.
Analyzes user photos to determine:
- Body type (rectangle, triangle, inverted triangle, hourglass, oval)
- Body alignment and posture
- Skin tone (fair, light, medium, olive, tan, brown, deep)
- Skin undertones (cool, warm, neutral)
- Face shape (oval, round, square, heart, diamond, oblong)
- Personalized style recommendations
Example:
>>> analyzer = StyleAnalyzer()
>>> result = analyzer.analyze_image("user_photo.jpg")
>>> print(result['body_type'])
'hourglass'
>>> print(result['skin_tone'])
'medium with warm undertones'
"""
def __init__(self, api_key: Optional[str] = None):
"""
Initialize the StyleAnalyzer.
Args:
api_key: Gemini API key. If None, reads from GEMINI_API_KEY environment variable.
Raises:
ImportError: If google-genai package is not installed
ValueError: If API key is not provided or found in environment
"""
if not GOOGLE_GENAI_AVAILABLE:
raise ImportError(
"google-genai package is required. Install it with: pip install google-genai"
)
# Load environment variables
load_dotenv()
# Get API key
self.api_key = api_key or os.getenv("GEMINI_API_KEY")
if not self.api_key:
raise ValueError(
"Gemini API key is required. Provide it via constructor parameter "
"or set GEMINI_API_KEY environment variable."
)
# Configure Gemini client
self.client = genai.Client(api_key=self.api_key)
# Use Gemini 2.5 Flash for analysis (fast and efficient)
self.model_name = "gemini-2.5-flash"
def _load_image(self, image: Union[str, Path, Image.Image, bytes]) -> Image.Image:
"""
Load image from various input formats.
Args:
image: Image as file path, PIL Image, or bytes
Returns:
PIL Image object
"""
if isinstance(image, (str, Path)):
return Image.open(image)
elif isinstance(image, Image.Image):
return image
elif isinstance(image, bytes):
return Image.open(io.BytesIO(image))
else:
raise ValueError(f"Unsupported image type: {type(image)}")
def _image_to_base64(self, image: Image.Image) -> str:
"""
Convert PIL Image to base64 string.
Args:
image: PIL Image object
Returns:
Base64-encoded image string
"""
buffer = io.BytesIO()
image.save(buffer, format="PNG")
buffer.seek(0)
return base64.b64encode(buffer.read()).decode('utf-8')
def analyze_image(
self,
image: Union[str, Path, Image.Image, bytes],
detailed: bool = True
) -> Dict[str, Any]:
"""
Analyze user image for style characteristics.
Args:
image: User photo (file path, PIL Image, or bytes)
detailed: If True, provides detailed analysis and recommendations
Returns:
Dictionary containing:
- body_type: Body shape classification
- body_alignment: Posture and alignment assessment
- skin_tone: Skin color classification
- skin_undertone: Cool, warm, or neutral undertone
- face_shape: Face shape classification
- height_estimate: Estimated height category (if full body visible)
- style_recommendations: Personalized fashion suggestions
- color_palette: Recommended colors based on skin tone
- analysis_details: Detailed explanation (if detailed=True)
"""
# Load image
pil_image = self._load_image(image)
# Prepare detailed analysis prompt
prompt = """
Analyze this person's image and provide a comprehensive style analysis based on PAKISTANI FASHION and cultural context.
Focus on the following aspects:
1. **BODY TYPE ANALYSIS**:
- Classify the body shape (rectangle, triangle/pear, inverted triangle, hourglass, oval/apple)
- Note the shoulder-to-hip ratio
- Identify the body frame (petite, average, tall)
- Assess body proportions
2. **BODY ALIGNMENT & POSTURE**:
- Evaluate posture (upright, slouched, forward head, etc.)
- Check shoulder alignment (level, tilted)
- Assess hip alignment
- Note any visible asymmetries
- Comment on overall body balance
3. **SKIN TONE ANALYSIS**:
- Identify skin tone (fair, light, medium, olive, tan, brown, deep)
- Determine skin undertone (cool/pink, warm/yellow-golden, neutral)
- Note any variations in skin tone across visible areas
- Assess skin texture and clarity (if visible)
4. **FACE SHAPE**:
- Classify face shape (oval, round, square, heart, diamond, oblong/rectangle)
- Note prominent features (cheekbones, jawline, forehead)
5. **HEIGHT ESTIMATION** (if full body is visible):
- Estimate height category (petite: <5'4", average: 5'4"-5'7", tall: >5'7")
- Base this on body proportions and limb-to-torso ratio
6. **PAKISTANI FASHION STYLE RECOMMENDATIONS**:
- Suggest PAKISTANI clothing styles that complement the body type (Kurta, Shalwar Kameez, Lehenga, Sharara, Gharara, Anarkali, etc.)
- Recommend cuts, silhouettes, and fits popular in Pakistani fashion
- Suggest traditional and contemporary fusion styles
- Provide neckline recommendations (boat neck, round neck, V-neck, collar neck, etc.) based on face shape
- Include dupatta/scarf styling suggestions
- Recommend embellishments and embroidery styles (Zari, Gota, Mirror work, Thread work, etc.)
7. **COLOR PALETTE** (Based on Pakistani Fashion Preferences):
- Recommend colors based on skin tone and undertone, considering popular Pakistani color palettes
- Suggest traditional Pakistani colors (pastels, jewel tones, earthy tones, bright festive colors)
- Include seasonal preferences (lawn season colors, winter wear, festive colors)
- Suggest colors to wear and colors to avoid
8. **PAKISTANI OUTFIT SUGGESTIONS**:
- Suggest 3-5 complete PAKISTANI outfit ideas that would suit this person
- Include both traditional and modern Pakistani styles
- For each outfit, provide:
* Name of the outfit style (e.g., "Elegant Anarkali Suit", "Modern Kurta Set", "Festive Sharara")
* Specific items (Kurta/Kameez, Shalwar/Trouser/Palazzo, Dupatta, accessories)
* Fabric suggestions (Lawn, Chiffon, Silk, Cotton, Karandi, Linen, etc.)
* Embellishment details
* Occasion suitability (casual, formal, festive, wedding, party)
- Make suggestions practical and culturally appropriate
Provide your analysis in the following JSON-like structure (but in natural language):
**Body Type**: [classification]
**Body Alignment**: [posture assessment]
**Skin Tone**: [tone] with [undertone] undertones
**Face Shape**: [shape]
**Height Estimate**: [category if visible, or "Cannot determine - upper body only"]
**Style Recommendations**:
- [Pakistani fashion recommendation 1 - with specific garment types]
- [Pakistani fashion recommendation 2 - with specific garment types]
- [Pakistani fashion recommendation 3 - with specific garment types]
- [Pakistani fashion recommendation 4 - styling tips]
**Color Palette**:
- Best colors: [list of colors popular in Pakistani fashion]
- Colors to avoid: [list]
**Outfit Suggestions**:
- [Pakistani Outfit 1 with name]: [detailed outfit description with fabrics and embellishments]
- [Pakistani Outfit 2 with name]: [detailed outfit description with fabrics and embellishments]
- [Pakistani Outfit 3 with name]: [detailed outfit description with fabrics and embellishments]
- [Pakistani Outfit 4 with name]: [detailed outfit description with fabrics and embellishments]
- [Pakistani Outfit 5 with name]: [detailed outfit description with fabrics and embellishments]
**Detailed Analysis**:
[Provide a comprehensive paragraph explaining the analysis and how the PAKISTANI fashion recommendations
will enhance the person's natural features, considering cultural preferences and modern trends]
Be professional, positive, and constructive. Focus on enhancing natural features
rather than criticizing. Provide actionable Pakistani fashion advice that considers both traditional
and contemporary styles. Consider the rich heritage of Pakistani fashion including regional variations.
"""
if not detailed:
prompt = """
Analyze this person's image briefly:
1. Body type
2. Posture/alignment
3. Skin tone with undertone
4. Face shape
5. Quick style suggestions
Be concise and provide just the key findings in a few sentences.
"""
try:
# Convert PIL image to bytes for Gemini
img_byte_arr = io.BytesIO()
pil_image.save(img_byte_arr, format='PNG')
img_byte_arr.seek(0)
# Generate analysis using Gemini
response = self.client.models.generate_content(
model=self.model_name,
contents=[prompt, pil_image]
)
# Parse response text
analysis_text = response.text
# Parse the structured response into a dictionary
result = self._parse_analysis(analysis_text)
# Add raw analysis text
result['raw_analysis'] = analysis_text
result['success'] = True
return result
except Exception as e:
print(f"[ERROR] Gemini API error: {str(e)}")
print(f"[ERROR] Full traceback: {traceback.format_exc()}")
return {
'success': False,
'error': str(e),
'message': 'Failed to analyze image'
}
def _parse_analysis(self, text: str) -> Dict[str, Any]:
"""
Parse the AI response text into structured data.
Args:
text: Raw text response from Gemini
Returns:
Structured dictionary with analysis results
"""
result = {
'body_type': '',
'body_alignment': '',
'skin_tone': '',
'skin_undertone': '',
'face_shape': '',
'height_estimate': '',
'style_recommendations': [],
'outfit_suggestions': [],
'color_palette': {
'best_colors': [],
'colors_to_avoid': []
},
'detailed_analysis': ''
}
lines = text.split('\n')
current_section = None
for line in lines:
line = line.strip()
# Skip empty lines
if not line:
continue
# Detect sections
if line.startswith('**Body Type**'):
current_section = 'body_type'
result['body_type'] = line.split(':', 1)[1].strip() if ':' in line else ''
elif line.startswith('**Body Alignment**'):
current_section = 'body_alignment'
result['body_alignment'] = line.split(':', 1)[1].strip() if ':' in line else ''
elif line.startswith('**Skin Tone**'):
current_section = 'skin_tone'
tone_text = line.split(':', 1)[1].strip() if ':' in line else ''
result['skin_tone'] = tone_text
# Extract undertone if present
if 'undertone' in tone_text.lower():
if 'warm' in tone_text.lower():
result['skin_undertone'] = 'warm'
elif 'cool' in tone_text.lower():
result['skin_undertone'] = 'cool'
elif 'neutral' in tone_text.lower():
result['skin_undertone'] = 'neutral'
elif line.startswith('**Face Shape**'):
current_section = 'face_shape'
result['face_shape'] = line.split(':', 1)[1].strip() if ':' in line else ''
elif line.startswith('**Height Estimate**'):
current_section = 'height_estimate'
result['height_estimate'] = line.split(':', 1)[1].strip() if ':' in line else ''
elif line.startswith('**Style Recommendations**'):
current_section = 'style_recommendations'
elif line.startswith('**Outfit Suggestions**'):
current_section = 'outfit_suggestions'
elif line.startswith('**Color Palette**'):
current_section = 'color_palette'
elif line.startswith('**Detailed Analysis**'):
current_section = 'detailed_analysis'
# Parse list items
elif line.startswith('-') or line.startswith('•'):
item = line[1:].strip()
# Clean up markdown formatting (* and ** for bold/italic)
item = item.replace('**', '').replace('*', '')
if current_section == 'style_recommendations':
result['style_recommendations'].append(item)
elif current_section == 'outfit_suggestions':
result['outfit_suggestions'].append(item)
elif current_section == 'color_palette':
if 'best' in item.lower() or 'wear' in item.lower():
# Extract colors from the line
colors = item.split(':', 1)[1].strip() if ':' in item else item
result['color_palette']['best_colors'] = [c.strip() for c in colors.split(',')]
elif 'avoid' in item.lower():
colors = item.split(':', 1)[1].strip() if ':' in item else item
result['color_palette']['colors_to_avoid'] = [c.strip() for c in colors.split(',')]
# Accumulate detailed analysis
elif current_section == 'detailed_analysis' and line:
if result['detailed_analysis']:
result['detailed_analysis'] += ' ' + line
else:
result['detailed_analysis'] = line
# If parsing didn't capture everything, store the whole text
if not result['body_type'] and not result['skin_tone']:
result['detailed_analysis'] = text
return result
def analyze_for_virtual_tryon(
self,
image: Union[str, Path, Image.Image, bytes]
) -> Dict[str, Any]:
"""
Specialized analysis for virtual try-on preparation.
Provides specific information needed for optimal virtual try-on results:
- Body measurements and proportions
- Best garment fits for body type
- Pose quality assessment
- Image quality check
Args:
image: User photo (file path, PIL Image, or bytes)
Returns:
Dictionary with virtual try-on specific analysis
"""
pil_image = self._load_image(image)
prompt = """
Analyze this image for virtual try-on readiness with PAKISTANI FASHION context. Provide:
1. **Image Quality**: Rate the image quality (excellent, good, fair, poor)
- Check lighting, clarity, resolution
- Assess if the person is clearly visible
2. **Pose Assessment**: Evaluate the pose for try-on
- Is the person facing forward?
- Are arms positioned well for clothing visualization?
- Is the full body or upper body visible?
- Rate pose quality: excellent, good, fair, poor
3. **Body Type for Try-On**: Quick classification for Pakistani garment fitting
- Body shape
- Frame size
- Suitability for different Pakistani outfit styles
4. **Pakistani Garment Fit Recommendations**:
- What types of Pakistani clothing would fit best (Kurta, Shalwar Kameez, Anarkali, Sharara, Gharara, etc.)
- Sizes to consider (Small, Medium, Large, XL for Pakistani wear)
- Style suggestions for this body type in Pakistani fashion context
- Dupatta and accessories recommendations
5. **Try-On Readiness Score**: Overall score from 1-10
- 10 = Perfect for virtual try-on of Pakistani outfits
- 1 = Poor quality, may not work well
6. **Improvement Suggestions**: If score < 8, suggest how to improve the photo for trying on Pakistani fashion
Be concise and practical. Focus on what matters for virtual try-on success with Pakistani clothing styles.
Consider the draping nature of Pakistani garments and cultural styling preferences.
"""
try:
# Convert PIL image to bytes for Gemini
img_byte_arr = io.BytesIO()
pil_image.save(img_byte_arr, format='PNG')
img_byte_arr.seek(0)
response = self.client.models.generate_content(
model=self.model_name,
contents=[prompt, pil_image]
)
analysis_text = response.text
return {
'success': True,
'analysis': analysis_text,
'raw_response': analysis_text,
'image_dimensions': {
'width': pil_image.width,
'height': pil_image.height
}
}
except Exception as e:
return {
'success': False,
'error': str(e),
'message': 'Failed to analyze image for virtual try-on'
}
# Example usage
if __name__ == "__main__":
import sys
if len(sys.argv) < 2:
print("Usage: python analyzer.py <image_path>")
sys.exit(1)
image_path = sys.argv[1]
if not os.path.exists(image_path):
print(f"Error: Image file not found: {image_path}")
sys.exit(1)
# Initialize analyzer
analyzer = StyleAnalyzer()
# Perform analysis
print("Analyzing image...")
result = analyzer.analyze_image(image_path, detailed=True)
if result['success']:
print("\n" + "="*60)
print("STYLE ANALYSIS REPORT")
print("="*60 + "\n")
print(f"Body Type: {result['body_type']}")
print(f"Body Alignment: {result['body_alignment']}")
print(f"Skin Tone: {result['skin_tone']}")
print(f"Face Shape: {result['face_shape']}")
print(f"Height Estimate: {result['height_estimate']}")
print("\nStyle Recommendations:")
for rec in result['style_recommendations']:
print(f" • {rec}")
if result['color_palette']['best_colors']:
print(f"\nBest Colors: {', '.join(result['color_palette']['best_colors'])}")
if result['color_palette']['colors_to_avoid']:
print(f"Colors to Avoid: {', '.join(result['color_palette']['colors_to_avoid'])}")
print(f"\nDetailed Analysis:\n{result['detailed_analysis']}")
print("\n" + "="*60)
else:
print(f"Analysis failed: {result.get('error', 'Unknown error')}")