import gradio as gr import requests import os import json import base64 from PIL import Image, ImageDraw, ImageFont import io import numpy as np import cv2 from typing import List, Tuple, Optional import logging from datetime import datetime import tempfile # Configure logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) class SalesforceConnector: """Handle Salesforce API connections and data retrieval""" def __init__(self): self.access_token = None self.instance_url = None self.session = requests.Session() def authenticate(self, client_id: str, client_secret: str, username: str, password: str, security_token: str = ""): """Authenticate with Salesforce using OAuth 2.0""" try: auth_url = "https://login.salesforce.com/services/oauth2/token" auth_data = { 'grant_type': 'password', 'client_id': client_id, 'client_secret': client_secret, 'username': username, 'password': password + security_token } response = self.session.post(auth_url, data=auth_data) response.raise_for_status() auth_result = response.json() self.access_token = auth_result['access_token'] self.instance_url = auth_result['instance_url'] self.session.headers.update({ 'Authorization': f'Bearer {self.access_token}', 'Content-Type': 'application/json' }) logger.info("Successfully authenticated with Salesforce") return True except requests.exceptions.RequestException as e: logger.error(f"Salesforce authentication failed: {e}") return False def fetch_dress_catalog(self) -> List[dict]: """Fetch dress catalog from Salesforce""" try: # Query for dress products (adjust SOQL query based on your Salesforce schema) query = """ SELECT Id, Name, Description, Product_Image_URL__c, Category__c, Price__c, Size__c, Color__c FROM Product2 WHERE Category__c = 'Dress' OR Category__c = 'Clothing' ORDER BY Name LIMIT 50 """ query_url = f"{self.instance_url}/services/data/v58.0/query" params = {'q': query} response = self.session.get(query_url, params=params) response.raise_for_status() result = response.json() dresses = result.get('records', []) logger.info(f"Fetched {len(dresses)} dresses from Salesforce") return dresses except requests.exceptions.RequestException as e: logger.error(f"Failed to fetch dress catalog: {e}") return self._get_sample_dresses() def _get_sample_dresses(self) -> List[dict]: """Return sample dress data for demo purposes""" return [ { "Id": "dress_001", "Name": "Elegant Evening Dress", "Description": "Beautiful black evening dress perfect for special occasions", "Product_Image_URL__c": "https://images.pexels.com/photos/1926769/pexels-photo-1926769.jpeg", "Category__c": "Dress", "Price__c": 299.99, "Size__c": "M", "Color__c": "Black" }, { "Id": "dress_002", "Name": "Summer Floral Dress", "Description": "Light and airy floral dress for summer occasions", "Product_Image_URL__c": "https://images.pexels.com/photos/1926769/pexels-photo-1926769.jpeg", "Category__c": "Dress", "Price__c": 149.99, "Size__c": "S", "Color__c": "Floral" }, { "Id": "dress_003", "Name": "Business Casual Dress", "Description": "Professional dress suitable for office wear", "Product_Image_URL__c": "https://images.pexels.com/photos/1926769/pexels-photo-1926769.jpeg", "Category__c": "Dress", "Price__c": 199.99, "Size__c": "L", "Color__c": "Navy" } ] class VirtualTryOnEngine: """Handle virtual try-on processing""" def __init__(self): self.model_loaded = False def process_tryon(self, person_image: Image.Image, dress_image: Image.Image, dress_info: dict) -> Tuple[Image.Image, str]: """Process virtual try-on between person and dress images""" try: # For demo purposes, we'll create a simple overlay effect # In production, you would use a proper virtual try-on model result_image = self._create_demo_tryon(person_image, dress_image, dress_info) confidence_score = "85%" return result_image, confidence_score except Exception as e: logger.error(f"Try-on processing failed: {e}") return person_image, "Error" def _create_demo_tryon(self, person_image: Image.Image, dress_image: Image.Image, dress_info: dict) -> Image.Image: """Create a demo try-on result by overlaying dress info""" # Resize images to standard size person_img = person_image.convert("RGB") person_img = person_img.resize((512, 768)) # Create a copy for the result result_img = person_img.copy() draw = ImageDraw.Draw(result_img) # Add dress information overlay try: font = ImageFont.load_default() except: font = None # Add semi-transparent overlay overlay = Image.new('RGBA', result_img.size, (0, 0, 0, 128)) result_img = Image.alpha_composite(result_img.convert('RGBA'), overlay).convert('RGB') # Add dress information text dress_name = dress_info.get('Name', 'Selected Dress') price = dress_info.get('Price__c', 0) color = dress_info.get('Color__c', 'N/A') size = dress_info.get('Size__c', 'N/A') text_lines = [ f"Virtual Try-On Result", f"Dress: {dress_name}", f"Price: ${price}", f"Color: {color}", f"Size: {size}", f"Confidence: 85%" ] y_offset = 20 for line in text_lines: draw.text((20, y_offset), line, fill="white", font=font) y_offset += 25 return result_img class VirtualTryOnApp: """Main application class""" def __init__(self): self.sf_connector = SalesforceConnector() self.tryon_engine = VirtualTryOnEngine() self.dress_catalog = [] self.selected_dress = None def initialize_salesforce(self, client_id: str, client_secret: str, username: str, password: str, security_token: str = ""): """Initialize Salesforce connection""" success = self.sf_connector.authenticate(client_id, client_secret, username, password, security_token) if success: self.dress_catalog = self.sf_connector.fetch_dress_catalog() return "✅ Successfully connected to Salesforce and loaded dress catalog!", self._get_dress_options() else: # Load sample data for demo self.dress_catalog = self.sf_connector._get_sample_dresses() return "⚠️ Using sample data (Salesforce connection failed)", self._get_dress_options() def _get_dress_options(self) -> List[str]: """Get dress options for dropdown""" return [f"{dress['Name']} - ${dress['Price__c']} ({dress['Color__c']})" for dress in self.dress_catalog] def select_dress(self, dress_selection: str) -> Tuple[str, str]: """Handle dress selection""" if not dress_selection or not self.dress_catalog: return "Please select a dress", "" # Find selected dress dress_name = dress_selection.split(' - ')[0] self.selected_dress = next((dress for dress in self.dress_catalog if dress['Name'] == dress_name), None) if self.selected_dress: dress_info = f""" **Selected Dress Details:** - **Name:** {self.selected_dress['Name']} - **Description:** {self.selected_dress['Description']} - **Price:** ${self.selected_dress['Price__c']} - **Color:** {self.selected_dress['Color__c']} - **Size:** {self.selected_dress['Size__c']} """ image_url = self.selected_dress.get('Product_Image_URL__c', '') return dress_info, image_url return "Dress not found", "" def process_virtual_tryon(self, person_image: Image.Image) -> Tuple[Image.Image, str]: """Process the virtual try-on""" if person_image is None: return None, "Please upload a person image" if self.selected_dress is None: return person_image, "Please select a dress first" try: # Load dress image from URL dress_url = self.selected_dress.get('Product_Image_URL__c', '') if dress_url: dress_response = requests.get(dress_url, timeout=10) dress_image = Image.open(io.BytesIO(dress_response.content)) else: # Create placeholder dress image dress_image = Image.new('RGB', (300, 400), color='lightblue') # Process virtual try-on result_image, confidence = self.tryon_engine.process_tryon(person_image, dress_image, self.selected_dress) status_message = f"✅ Virtual try-on completed! Confidence: {confidence}" return result_image, status_message except Exception as e: logger.error(f"Virtual try-on failed: {e}") return person_image, f"❌ Try-on failed: {str(e)}" # Initialize the app app = VirtualTryOnApp() def setup_salesforce_connection(client_id, client_secret, username, password, security_token): """Setup Salesforce connection and return status and dress options""" status, dress_options = app.initialize_salesforce(client_id, client_secret, username, password, security_token) return status, gr.Dropdown(choices=dress_options, value=None) def handle_dress_selection(dress_selection): """Handle dress selection and return dress info and image""" dress_info, image_url = app.select_dress(dress_selection) # Try to load dress image dress_image = None if image_url: try: response = requests.get(image_url, timeout=10) dress_image = Image.open(io.BytesIO(response.content)) except: dress_image = None return dress_info, dress_image def process_tryon(person_image): """Process virtual try-on""" return app.process_virtual_tryon(person_image) # Custom CSS for better styling custom_css = """ .gradio-container { font-family: 'Inter', sans-serif; max-width: 1200px !important; margin: 0 auto; } .header-text { text-align: center; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; font-size: 2.5rem; font-weight: bold; margin-bottom: 1rem; } .section-header { background: linear-gradient(90deg, #4facfe 0%, #00f2fe 100%); padding: 1rem; border-radius: 8px; color: white; font-weight: bold; margin: 1rem 0; } .status-success { background-color: #d4edda; color: #155724; padding: 1rem; border-radius: 8px; border: 1px solid #c3e6cb; } .status-error { background-color: #f8d7da; color: #721c24; padding: 1rem; border-radius: 8px; border: 1px solid #f5c6cb; } .image-container { border: 2px solid #e1e5e9; border-radius: 12px; padding: 1rem; background: white; box-shadow: 0 2px 8px rgba(0,0,0,0.1); } .tryon-results { background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); padding: 2rem; border-radius: 12px; margin-top: 1rem; } """ # Create the Gradio interface with gr.Blocks(css=custom_css, title="Virtual Try-On for Clothing") as demo: # Header gr.HTML("""
Experience the future of fashion with AI-powered virtual try-on technology
""") # Salesforce Configuration Section with gr.Accordion("🔧 Salesforce Configuration", open=True): gr.HTML('Upload your photo, select a dress from your Salesforce catalog, and see how it looks on you instantly!