import os import io import base64 import json import requests from PIL import Image import numpy as np from flask import Flask, render_template, request, jsonify, send_from_directory from flask_cors import CORS import torch from transformers import ( AutoImageProcessor, AutoModelForImageClassification, BlipProcessor, BlipForConditionalGeneration, pipeline ) import cv2 from skimage import measure import logging import threading import time import socket import subprocess import sys from datetime import datetime import psutil from transformers import CLIPProcessor, CLIPModel # Configure logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) def convert_numpy_types(obj): """Convert numpy types to Python native types for JSON serialization""" if isinstance(obj, np.integer): return int(obj) elif isinstance(obj, np.floating): return float(obj) elif isinstance(obj, np.ndarray): return obj.tolist() elif isinstance(obj, dict): return {key: convert_numpy_types(value) for key, value in obj.items()} elif isinstance(obj, list): return [convert_numpy_types(item) for item in obj] else: return obj def find_free_port(start_port=7860, max_attempts=10): """Find a free port starting from start_port""" for port in range(start_port, start_port + max_attempts): try: with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.bind(('localhost', port)) return port except OSError: continue return start_port # Return default port if no free port found def kill_process_on_port(port): """Kill process running on a specific port""" try: if sys.platform.startswith('win'): # Windows cmd = f'netstat -ano | findstr :{port}' result = subprocess.run(cmd, shell=True, capture_output=True, text=True) if result.stdout: lines = result.stdout.strip().split('\n') for line in lines: if f':{port}' in line: parts = line.split() if len(parts) >= 5: pid = parts[-1] subprocess.run(f'taskkill /PID {pid} /F', shell=True) logger.info(f"Killed process {pid} on port {port}") else: # Linux/Mac cmd = f'lsof -ti:{port}' result = subprocess.run(cmd, shell=True, capture_output=True, text=True) if result.stdout.strip(): pids = result.stdout.strip().split('\n') for pid in pids: if pid: subprocess.run(f'kill -9 {pid}', shell=True) logger.info(f"Killed process {pid} on port {port}") except Exception as e: logger.warning(f"Could not kill process on port {port}: {e}") # Initialize Flask app with correct template folder app = Flask(__name__, template_folder='templates') app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # 16MB max file size CORS(app) # Global variables for models room_classifier = None image_captioner = None quality_analyzer = None yolo_model = None clip_processor = None clip_model = None def load_models(): """Load advanced AI models for comprehensive analysis""" global room_classifier, image_captioner, object_detector, clip_processor, clip_model try: logger.info("Loading advanced AI models...") # 1. Room Classification Model room_classifier = pipeline( "image-classification", model="andupets/real-estate-image-classification", device=0 if torch.cuda.is_available() else -1 ) logger.info("✓ Room classification model loaded") # 2. Advanced Image Captioning Model image_captioner = pipeline( "image-to-text", model="Salesforce/blip-image-captioning-base", device=0 if torch.cuda.is_available() else -1 ) logger.info("✓ Image captioning model loaded") # 3. Advanced Object Detection Model object_detector = pipeline( "object-detection", model="facebook/detr-resnet-50", device=0 if torch.cuda.is_available() else -1 ) logger.info("✓ Object detection model loaded") # 4. CLIP Model for Advanced Scene Understanding try: clip_processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32") clip_model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32") if torch.cuda.is_available(): clip_model = clip_model.to('cuda') logger.info("✓ CLIP model loaded for scene understanding") except Exception as e: logger.warning(f"CLIP model loading failed: {e}") clip_processor = None clip_model = None # 5. Advanced Image Quality Assessment Model try: from transformers import AutoImageProcessor, AutoModelForImageClassification quality_processor = AutoImageProcessor.from_pretrained("microsoft/resnet-50") quality_model = AutoModelForImageClassification.from_pretrained("microsoft/resnet-50") if torch.cuda.is_available(): quality_model = quality_model.to('cuda') logger.info("✓ Advanced quality assessment model loaded") except Exception as e: logger.warning(f"Quality model loading failed: {e}") quality_processor = None quality_model = None # 6. YOLO Model for Additional Object Detection try: from ultralytics import YOLO yolo_model = YOLO('yolov8n.pt') logger.info("✓ YOLO model loaded for enhanced object detection") except Exception as e: logger.warning(f"YOLO model loading failed: {e}") yolo_model = None logger.info("All advanced AI models loaded successfully!") return True except Exception as e: logger.error(f"Error loading models: {str(e)}") return False def detect_objects_advanced(image): """Advanced AI-powered object detection using multiple models""" try: # Convert PIL image to numpy array img_array = np.array(image) # Ensure we have a valid image if img_array.size == 0: raise ValueError("Empty image array") # Multiple AI models for comprehensive object detection detected_objects = [] object_analysis = {} # 1. DETR (DEtection TRansformer) - Primary detection try: from transformers import DetrImageProcessor, DetrForObjectDetection import torch processor = DetrImageProcessor.from_pretrained("facebook/detr-resnet-50") model = DetrForObjectDetection.from_pretrained("facebook/detr-resnet-50") # Prepare image for DETR inputs = processor(images=image, return_tensors="pt") with torch.no_grad(): outputs = model(**inputs) # Post-process outputs target_sizes = torch.tensor([image.size[::-1]]) results = processor.post_process_object_detection(outputs, target_sizes=target_sizes, threshold=0.5)[0] for score, label, box in zip(results["scores"], results["labels"], results["boxes"]): detected_objects.append({ "label": model.config.id2label[label.item()], "confidence": float(score.item()), # Convert to Python float "bbox": [float(x) for x in box.tolist()] # Convert to Python floats }) except Exception as e: logger.warning(f"DETR detection failed: {str(e)}") # 2. YOLO v8 (if available) for additional detection try: from ultralytics import YOLO # Load YOLO model yolo_model = YOLO('yolov8n.pt') # Run inference results = yolo_model(image) for result in results: boxes = result.boxes if boxes is not None: for box in boxes: # Get box coordinates x1, y1, x2, y2 = box.xyxy[0].cpu().numpy() confidence = float(box.conf[0].cpu().numpy()) # Convert to Python float class_id = int(box.cls[0].cpu().numpy()) class_name = yolo_model.names[class_id] # Add if not already detected by DETR if not any(obj["label"].lower() == class_name.lower() for obj in detected_objects): detected_objects.append({ "label": class_name, "confidence": confidence, "bbox": [float(x1), float(y1), float(x2), float(y2)] # Convert to Python floats }) except Exception as e: logger.warning(f"YOLO detection failed: {str(e)}") # 3. Scene understanding with CLIP try: from transformers import CLIPProcessor, CLIPModel clip_processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32") clip_model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32") # Define real estate specific text prompts real_estate_concepts = [ "modern furniture", "luxury interior", "kitchen appliances", "bathroom fixtures", "bedroom furniture", "living room setup", "dining area", "home office", "outdoor space", "balcony", "garden", "parking space", "storage area", "lighting fixtures", "flooring", "wall decor", "window treatments", "architectural features", "high ceilings", "open floor plan" ] # Process image and text inputs = clip_processor(images=image, text=real_estate_concepts, return_tensors="pt", padding=True) with torch.no_grad(): outputs = clip_model(**inputs) logits_per_image = outputs.logits_per_image probs = logits_per_image.softmax(dim=-1) # Get top matches top_concepts = [] for i, prob in enumerate(probs[0]): if prob > 0.3: # Threshold for relevance top_concepts.append({ "concept": real_estate_concepts[i], "confidence": float(prob.item()) # Convert to Python float }) object_analysis["scene_concepts"] = sorted(top_concepts, key=lambda x: x["confidence"], reverse=True)[:5] except Exception as e: logger.warning(f"CLIP analysis failed: {str(e)}") object_analysis["scene_concepts"] = [] # 4. Advanced object categorization and analysis if detected_objects: # Categorize objects by type furniture_objects = [obj for obj in detected_objects if any(keyword in obj["label"].lower() for keyword in ["chair", "table", "bed", "sofa", "desk", "cabinet", "shelf"])] appliance_objects = [obj for obj in detected_objects if any(keyword in obj["label"].lower() for keyword in ["refrigerator", "oven", "microwave", "dishwasher", "washer", "dryer"])] fixture_objects = [obj for obj in detected_objects if any(keyword in obj["label"].lower() for keyword in ["sink", "toilet", "bathtub", "shower", "faucet", "light", "lamp"])] # Calculate object density and distribution img_area = img_array.shape[0] * img_array.shape[1] object_density = float(len(detected_objects) / (img_area / 10000)) # Convert to Python float # Analyze object positioning center_x, center_y = img_array.shape[1] / 2, img_array.shape[0] / 2 centered_objects = 0 for obj in detected_objects: bbox = obj["bbox"] obj_center_x = (bbox[0] + bbox[2]) / 2 obj_center_y = (bbox[1] + bbox[3]) / 2 # Check if object is in center region if (abs(obj_center_x - center_x) < center_x * 0.3 and abs(obj_center_y - center_y) < center_y * 0.3): centered_objects += 1 object_analysis.update({ "total_objects": len(detected_objects), "furniture_count": len(furniture_objects), "appliance_count": len(appliance_objects), "fixture_count": len(fixture_objects), "object_density": object_density, "centered_objects": centered_objects, "composition_balance": float(centered_objects / len(detected_objects)) if detected_objects else 0.0, # Convert to Python float "object_categories": { "furniture": [obj["label"] for obj in furniture_objects], "appliances": [obj["label"] for obj in appliance_objects], "fixtures": [obj["label"] for obj in fixture_objects], "other": [obj["label"] for obj in detected_objects if obj not in furniture_objects + appliance_objects + fixture_objects] } }) else: # Fallback analysis when no objects detected object_analysis.update({ "total_objects": 0, "furniture_count": 0, "appliance_count": 0, "fixture_count": 0, "object_density": 0.0, "centered_objects": 0, "composition_balance": 0.0, "object_categories": {"furniture": [], "appliances": [], "fixtures": [], "other": []} }) # 5. Dynamic room type inference from objects room_type_confidence = {} # Kitchen indicators kitchen_indicators = ["refrigerator", "oven", "microwave", "dishwasher", "sink", "stove"] kitchen_score = sum(1 for obj in detected_objects if any(indicator in obj["label"].lower() for indicator in kitchen_indicators)) room_type_confidence["kitchen"] = min(1.0, kitchen_score / 3) # Bathroom indicators bathroom_indicators = ["toilet", "bathtub", "shower", "sink", "mirror"] bathroom_score = sum(1 for obj in detected_objects if any(indicator in obj["label"].lower() for indicator in bathroom_indicators)) room_type_confidence["bathroom"] = min(1.0, bathroom_score / 2) # Bedroom indicators bedroom_indicators = ["bed", "nightstand", "dresser", "wardrobe"] bedroom_score = sum(1 for obj in detected_objects if any(indicator in obj["label"].lower() for indicator in bedroom_indicators)) room_type_confidence["bedroom"] = min(1.0, bedroom_score / 2) # Living room indicators living_indicators = ["sofa", "tv", "coffee table", "armchair", "fireplace"] living_score = sum(1 for obj in detected_objects if any(indicator in obj["label"].lower() for indicator in living_indicators)) room_type_confidence["living room"] = min(1.0, living_score / 2) object_analysis["room_type_inference"] = room_type_confidence return { "objects": detected_objects, "analysis": object_analysis } except Exception as e: logger.error(f"Error in object detection: {str(e)}") return { "objects": [], "analysis": { "total_objects": 0, "furniture_count": 0, "appliance_count": 0, "fixture_count": 0, "object_density": 0.0, "centered_objects": 0, "composition_balance": 0.0, "object_categories": {"furniture": [], "appliances": [], "fixtures": [], "other": []}, "room_type_inference": {}, "scene_concepts": [] } } def analyze_image_quality(image): """Advanced AI-powered image quality analysis using multiple models""" try: # Convert PIL image to numpy array img_array = np.array(image) # Ensure we have a valid image if img_array.size == 0: raise ValueError("Empty image array") # Convert to grayscale for analysis if len(img_array.shape) == 3: gray = cv2.cvtColor(img_array, cv2.COLOR_RGB2GRAY) else: gray = img_array # Ensure we have valid dimensions if gray.shape[0] < 10 or gray.shape[1] < 10: raise ValueError("Image too small for analysis") # Advanced AI-based quality metrics quality_metrics = {} # 1. BRISQUE (Blind/Referenceless Image Spatial Quality Evaluator) try: from skimage.metrics import structural_similarity as ssim from skimage.filters import sobel # Calculate BRISQUE-like features sobel_img = sobel(gray) quality_metrics['sharpness'] = float(np.std(sobel_img)) # Local binary pattern for texture analysis from skimage.feature import local_binary_pattern lbp = local_binary_pattern(gray, P=8, R=1, method='uniform') quality_metrics['texture_quality'] = float(np.std(lbp)) except: quality_metrics['sharpness'] = float(cv2.Laplacian(gray, cv2.CV_64F).var()) quality_metrics['texture_quality'] = 50.0 # 2. Advanced brightness analysis with histogram hist = cv2.calcHist([gray], [0], None, [256], [0, 256]) hist_norm = hist.ravel() / hist.sum() # Calculate multiple brightness metrics quality_metrics['brightness_mean'] = float(np.mean(gray)) quality_metrics['brightness_std'] = float(np.std(gray)) quality_metrics['brightness_skew'] = float(np.mean(((gray - np.mean(gray)) / np.std(gray)) ** 3)) quality_metrics['brightness_kurtosis'] = float(np.mean(((gray - np.mean(gray)) / np.std(gray)) ** 4)) # 3. Advanced contrast analysis quality_metrics['contrast'] = float(np.std(gray)) quality_metrics['contrast_ratio'] = float(np.max(gray) / (np.min(gray) + 1e-8)) # 4. Noise analysis using multiple methods try: # Structural similarity for noise blurred = cv2.GaussianBlur(gray, (5, 5), 0) quality_metrics['noise_level'] = 1 - ssim(gray, blurred) # Wavelet-based noise estimation import pywt coeffs = pywt.wavedec2(gray, 'db1', level=1) detail_coeffs = coeffs[1] quality_metrics['wavelet_noise'] = float(np.std(detail_coeffs[0])) except: quality_metrics['noise_level'] = 0.05 quality_metrics['wavelet_noise'] = 10.0 # 5. Resolution and composition analysis height, width = gray.shape quality_metrics['resolution'] = f"{width}x{height}" quality_metrics['aspect_ratio'] = width / height quality_metrics['pixel_density'] = (width * height) / 10000 # 6. Composition analysis using rule of thirds thirds_h = height // 3 thirds_w = width // 3 # Check intersection points of rule of thirds intersection_points = [ gray[thirds_h, thirds_w], gray[thirds_h, 2*thirds_w], gray[2*thirds_h, thirds_w], gray[2*thirds_h, 2*thirds_w] ] quality_metrics['composition_score'] = float(np.std(intersection_points)) # 7. Color analysis (if color image) if len(img_array.shape) == 3: # Convert to different color spaces hsv = cv2.cvtColor(img_array, cv2.COLOR_RGB2HSV) lab = cv2.cvtColor(img_array, cv2.COLOR_RGB2LAB) quality_metrics['color_saturation'] = float(np.mean(hsv[:, :, 1])) quality_metrics['color_variance'] = float(np.std(lab)) quality_metrics['color_balance'] = float(np.std([np.mean(img_array[:, :, i]) for i in range(3)])) else: quality_metrics['color_saturation'] = 0.0 quality_metrics['color_variance'] = 0.0 quality_metrics['color_balance'] = 0.0 # AI-based quality scoring using weighted combination quality_score = 0 quality_issues = [] # Dynamic scoring based on image characteristics # Brightness scoring (0-20 points) brightness_score = 0 if quality_metrics['brightness_mean'] < 30: quality_issues.append("Image is extremely dark") brightness_score = 2 elif quality_metrics['brightness_mean'] < 50: quality_issues.append("Image is too dark") brightness_score = 8 elif quality_metrics['brightness_mean'] > 220: quality_issues.append("Image is overexposed") brightness_score = 5 elif quality_metrics['brightness_mean'] > 180: quality_issues.append("Image is somewhat overexposed") brightness_score = 12 else: brightness_score = 20 # Contrast scoring (0-20 points) contrast_score = 0 if quality_metrics['contrast'] < 15: quality_issues.append("Very low contrast") contrast_score = 2 elif quality_metrics['contrast'] < 30: quality_issues.append("Low contrast") contrast_score = 8 else: contrast_score = 20 # Sharpness scoring (0-20 points) sharpness_score = 0 if quality_metrics['sharpness'] < 30: quality_issues.append("Image is very blurry") sharpness_score = 2 elif quality_metrics['sharpness'] < 60: quality_issues.append("Image appears blurry") sharpness_score = 8 else: sharpness_score = 20 # Noise scoring (0-20 points) noise_score = 0 if quality_metrics['noise_level'] > 0.2: quality_issues.append("High noise level") noise_score = 5 elif quality_metrics['noise_level'] > 0.1: quality_issues.append("Moderate noise level") noise_score = 12 else: noise_score = 20 # Resolution scoring (0-10 points) resolution_score = 0 if quality_metrics['pixel_density'] < 20: quality_issues.append("Very low resolution") resolution_score = 2 elif quality_metrics['pixel_density'] < 50: quality_issues.append("Low resolution") resolution_score = 5 else: resolution_score = 10 # Composition scoring (0-10 points) composition_score = min(10, quality_metrics['composition_score'] / 10) if composition_score < 3: quality_issues.append("Poor composition") # Calculate total score quality_score = brightness_score + contrast_score + sharpness_score + noise_score + resolution_score + composition_score quality_score = min(100, quality_score) # Dynamic quality level determination if quality_score >= 90: quality_level = "Exceptional Quality" elif quality_score >= 80: quality_level = "High Quality" elif quality_score >= 70: quality_level = "Good Quality" elif quality_score >= 50: quality_level = "Medium Quality" else: quality_level = "Low Quality" return { "quality_level": quality_level, "quality_score": quality_score, "issues": quality_issues, "metrics": quality_metrics } except Exception as e: logger.error(f"Error in quality analysis: {str(e)}") return { "quality_level": "Analysis Failed", "quality_score": 0, "issues": ["Unable to analyze image quality"], "metrics": {} } def get_room_type_description(room_type): """Get detailed description for room types""" descriptions = { "bathroom": "A bathroom with toilet, sink, and shower/bathtub facilities", "bedroom": "A sleeping area with bed and bedroom furniture", "dining room": "A formal dining area with table and chairs for meals", "house facade": "The exterior front view of a house or building", "kitchen": "A cooking area with appliances, countertops, and storage", "living room": "A main living area with seating and entertainment space", "sao paulo apartment facade": "Exterior view of an apartment building" } return descriptions.get(room_type, f"A {room_type} area") def assess_property_image_quality(room_classification, quality_analysis, object_detection, image_caption): """Advanced AI-powered property image assessment using dynamic analysis""" try: # Initialize assessment components assessment = { "overall_score": 0, "strengths": [], "weaknesses": [], "recommendations": [], "market_appeal": {}, "technical_analysis": {}, "composition_analysis": {}, "professional_grade": False } # 1. Dynamic Room Classification Analysis (0-25 points) room_score = 0 room_confidence = room_classification.get('confidence', 0) room_type = room_classification.get('room_type', 'unknown') # AI-based room type validation if room_confidence > 0.8: room_score = 25 assessment["strengths"].append(f"Clear {room_type} identification with high confidence") elif room_confidence > 0.6: room_score = 20 assessment["strengths"].append(f"Good {room_type} identification") elif room_confidence > 0.4: room_score = 15 assessment["weaknesses"].append(f"Uncertain room type identification") else: room_score = 5 assessment["weaknesses"].append("Poor room type identification") # Cross-validate with object detection object_room_inference = object_detection.get('analysis', {}).get('room_type_inference', {}) if room_type in object_room_inference: object_confidence = object_room_inference[room_type] if object_confidence > 0.5: room_score += 5 # Bonus for consistency assessment["strengths"].append("Object detection confirms room type") else: room_score -= 5 # Penalty for inconsistency assessment["weaknesses"].append("Object detection contradicts room type") # 2. Advanced Quality Analysis (0-30 points) quality_score = 0 quality_metrics = quality_analysis.get('metrics', {}) quality_level = quality_analysis.get('quality_level', 'Unknown') quality_issues = quality_analysis.get('issues', []) # Dynamic quality scoring based on multiple factors base_quality = quality_analysis.get('quality_score', 0) # Technical quality factors brightness_score = 0 brightness_mean = quality_metrics.get('brightness_mean', 128) if 60 <= brightness_mean <= 180: brightness_score = 8 elif 40 <= brightness_mean <= 200: brightness_score = 5 else: brightness_score = 2 contrast_score = 0 contrast = quality_metrics.get('contrast', 0) if contrast > 40: contrast_score = 8 elif contrast > 25: contrast_score = 5 else: contrast_score = 2 sharpness_score = 0 sharpness = quality_metrics.get('sharpness', 0) if sharpness > 80: sharpness_score = 8 elif sharpness > 50: sharpness_score = 5 else: sharpness_score = 2 noise_score = 0 noise_level = quality_metrics.get('noise_level', 0) if noise_level < 0.05: noise_score = 6 elif noise_level < 0.1: noise_score = 4 else: noise_score = 1 quality_score = brightness_score + contrast_score + sharpness_score + noise_score # Add quality issues to weaknesses for issue in quality_issues: assessment["weaknesses"].append(f"Quality: {issue}") # 3. Advanced Object Detection Analysis (0-25 points) object_score = 0 object_analysis = object_detection.get('analysis', {}) detected_objects = object_detection.get('objects', []) # Object richness scoring total_objects = object_analysis.get('total_objects', 0) if total_objects >= 8: object_score += 10 assessment["strengths"].append("Rich object content enhances property appeal") elif total_objects >= 5: object_score += 7 assessment["strengths"].append("Good object variety") elif total_objects >= 3: object_score += 4 else: object_score += 1 assessment["weaknesses"].append("Limited object content") # Object relevance scoring furniture_count = object_analysis.get('furniture_count', 0) appliance_count = object_analysis.get('appliance_count', 0) fixture_count = object_analysis.get('fixture_count', 0) if furniture_count > 0: object_score += 5 if appliance_count > 0: object_score += 5 if fixture_count > 0: object_score += 5 # Composition balance composition_balance = object_analysis.get('composition_balance', 0) if composition_balance > 0.6: object_score += 5 assessment["strengths"].append("Well-balanced object composition") elif composition_balance < 0.3: object_score -= 3 assessment["weaknesses"].append("Poor object distribution") # 4. Dynamic Caption Quality Analysis (0-20 points) caption_score = 0 caption = image_caption.get('caption', '') if caption: # Analyze caption length and content caption_length = len(caption.split()) # Check for real estate keywords real_estate_keywords = ['room', 'kitchen', 'bathroom', 'bedroom', 'living', 'dining', 'modern', 'luxury', 'spacious', 'bright', 'clean', 'furnished'] keyword_count = sum(1 for keyword in real_estate_keywords if keyword.lower() in caption.lower()) if caption_length >= 10 and keyword_count >= 3: caption_score = 20 assessment["strengths"].append("Comprehensive and relevant caption") elif caption_length >= 8 and keyword_count >= 2: caption_score = 15 assessment["strengths"].append("Good descriptive caption") elif caption_length >= 5: caption_score = 10 else: caption_score = 5 assessment["weaknesses"].append("Limited caption description") else: assessment["weaknesses"].append("No caption generated") # 5. Calculate Overall Score with Dynamic Weighting overall_score = room_score + quality_score + object_score + caption_score # Normalize to 100-point scale overall_score = min(100, overall_score) # 6. Advanced Market Appeal Analysis market_appeal = {} # Professional grade determination if overall_score >= 85: assessment["professional_grade"] = True market_appeal["level"] = "Premium" market_appeal["description"] = "Professional-grade image suitable for luxury listings" elif overall_score >= 75: assessment["professional_grade"] = True market_appeal["level"] = "Professional" market_appeal["description"] = "High-quality image for professional listings" elif overall_score >= 60: market_appeal["level"] = "Standard" market_appeal["description"] = "Acceptable quality for standard listings" else: market_appeal["level"] = "Needs Improvement" market_appeal["description"] = "Image requires enhancement before listing" # Target audience analysis if room_type in ['kitchen', 'bathroom'] and quality_score > 20: market_appeal["target_audience"] = "Home buyers, Investors" elif room_type in ['bedroom', 'living room'] and object_score > 15: market_appeal["target_audience"] = "Families, Young professionals" else: market_appeal["target_audience"] = "General buyers" # 7. Dynamic Recommendations Generation recommendations = [] # Quality-based recommendations if brightness_mean < 50: recommendations.append("Increase lighting or use HDR techniques") elif brightness_mean > 200: recommendations.append("Reduce exposure to avoid overexposure") if contrast < 25: recommendations.append("Enhance contrast in post-processing") if sharpness < 50: recommendations.append("Use tripod or image stabilization for sharper photos") if noise_level > 0.1: recommendations.append("Use noise reduction software") # Object-based recommendations if total_objects < 3: recommendations.append("Include more furniture or decorative elements") if composition_balance < 0.4: recommendations.append("Reposition camera for better object distribution") # Room-specific recommendations if room_type == 'kitchen' and appliance_count < 2: recommendations.append("Highlight kitchen appliances and features") elif room_type == 'bathroom' and fixture_count < 2: recommendations.append("Showcase bathroom fixtures and amenities") # Technical recommendations if not assessment["professional_grade"]: recommendations.append("Consider professional photography services") assessment["recommendations"] = recommendations assessment["overall_score"] = overall_score assessment["market_appeal"] = market_appeal # 8. Technical Analysis Summary assessment["technical_analysis"] = { "room_classification_score": room_score, "quality_analysis_score": quality_score, "object_detection_score": object_score, "caption_quality_score": caption_score, "composition_balance": composition_balance, "object_density": object_analysis.get('object_density', 0), "quality_metrics_summary": { "brightness": round(brightness_mean, 1), "contrast": round(contrast, 1), "sharpness": round(sharpness, 1), "noise_level": round(noise_level, 3) } } return assessment except Exception as e: logger.error(f"Error in property assessment: {str(e)}") return { "overall_score": 0, "strengths": [], "weaknesses": ["Assessment failed due to technical error"], "recommendations": ["Please try again with a different image"], "market_appeal": {"level": "Unknown", "description": "Unable to assess"}, "professional_grade": False, "technical_analysis": {} } def estimate_room_size(image, room_type='unknown'): """Advanced AI-powered room size estimation using multiple analysis methods""" try: # Convert PIL image to numpy array img_array = np.array(image) # Get image dimensions height, width = img_array.shape[:2] image_area = height * width # 1. Object-based size estimation object_analysis = detect_objects_advanced(image) detected_objects = object_analysis.get('objects', []) object_analysis_data = object_analysis.get('analysis', {}) # Categorize objects by typical sizes large_furniture = [obj for obj in detected_objects if obj['label'].lower() in ['bed', 'sofa', 'couch', 'dining table', 'kitchen island']] medium_furniture = [obj for obj in detected_objects if obj['label'].lower() in ['chair', 'desk', 'cabinet', 'dresser', 'nightstand']] small_furniture = [obj for obj in detected_objects if obj['label'].lower() in ['lamp', 'plant', 'vase', 'picture frame']] # 2. Object density analysis total_objects = len(detected_objects) object_density = object_analysis_data.get('object_density', 0) # 3. Perspective and depth analysis # Analyze object positioning for depth perception if detected_objects: # Calculate object distribution across image x_positions = [] y_positions = [] object_sizes = [] for obj in detected_objects: bbox = obj['bbox'] x_center = (bbox[0] + bbox[2]) / 2 y_center = (bbox[1] + bbox[3]) / 2 obj_width = bbox[2] - bbox[0] obj_height = bbox[3] - bbox[1] obj_area = obj_width * obj_height x_positions.append(x_center) y_positions.append(y_center) object_sizes.append(obj_area) # Calculate spatial distribution x_variance = float(np.var(x_positions)) if len(x_positions) > 1 else 0.0 y_variance = float(np.var(y_positions)) if len(y_positions) > 1 else 0.0 avg_object_size = float(np.mean(object_sizes)) if object_sizes else 0.0 # Depth perception indicators size_variance = float(np.var(object_sizes)) if len(object_sizes) > 1 else 0.0 depth_indicator = float(size_variance / (avg_object_size + 1e-8)) else: x_variance = y_variance = avg_object_size = depth_indicator = 0.0 # 4. Advanced size estimation algorithm size_score = 0 size_factors = {} # Object count factor (0-30 points) if total_objects >= 10: size_score += 30 size_factors["object_count"] = "Very High" elif total_objects >= 7: size_score += 25 size_factors["object_count"] = "High" elif total_objects >= 5: size_score += 20 size_factors["object_count"] = "Medium-High" elif total_objects >= 3: size_score += 15 size_factors["object_count"] = "Medium" elif total_objects >= 1: size_score += 10 size_factors["object_count"] = "Low" else: size_factors["object_count"] = "Very Low" # Furniture type factor (0-25 points) furniture_score = 0 if len(large_furniture) >= 3: furniture_score = 25 size_factors["furniture_type"] = "Multiple large pieces" elif len(large_furniture) >= 2: furniture_score = 20 size_factors["furniture_type"] = "Several large pieces" elif len(large_furniture) >= 1: furniture_score = 15 size_factors["furniture_type"] = "Some large pieces" elif len(medium_furniture) >= 3: furniture_score = 12 size_factors["furniture_type"] = "Multiple medium pieces" elif len(medium_furniture) >= 1: furniture_score = 8 size_factors["furniture_type"] = "Some medium pieces" else: furniture_score = 5 size_factors["furniture_type"] = "Small pieces only" size_score += furniture_score # Object density factor (0-20 points) if object_density > 15: size_score += 20 size_factors["object_density"] = "Very High" elif object_density > 10: size_score += 15 size_factors["object_density"] = "High" elif object_density > 5: size_score += 10 size_factors["object_density"] = "Medium" elif object_density > 2: size_score += 5 size_factors["object_density"] = "Low" else: size_factors["object_density"] = "Very Low" # Spatial distribution factor (0-15 points) spatial_score = 0 if x_variance > 10000 and y_variance > 10000: spatial_score = 15 size_factors["spatial_distribution"] = "Wide spread" elif x_variance > 5000 or y_variance > 5000: spatial_score = 10 size_factors["spatial_distribution"] = "Moderate spread" elif x_variance > 1000 or y_variance > 1000: spatial_score = 5 size_factors["spatial_distribution"] = "Limited spread" else: size_factors["spatial_distribution"] = "Concentrated" size_score += spatial_score # Depth perception factor (0-10 points) if depth_indicator > 0.5: size_score += 10 size_factors["depth_perception"] = "Strong depth" elif depth_indicator > 0.2: size_score += 7 size_factors["depth_perception"] = "Moderate depth" elif depth_indicator > 0.1: size_score += 4 size_factors["depth_perception"] = "Limited depth" else: size_factors["depth_perception"] = "Flat perspective" # 5. Dynamic size classification if size_score >= 80: estimated_size = "Very Large (300+ sq ft)" size_category = "XL" confidence = "High" elif size_score >= 65: estimated_size = "Large (200-300 sq ft)" size_category = "L" confidence = "High" elif size_score >= 50: estimated_size = "Medium-Large (150-200 sq ft)" size_category = "ML" confidence = "Medium" elif size_score >= 35: estimated_size = "Medium (100-150 sq ft)" size_category = "M" confidence = "Medium" elif size_score >= 20: estimated_size = "Small-Medium (80-100 sq ft)" size_category = "SM" confidence = "Medium" elif size_score >= 10: estimated_size = "Small (50-80 sq ft)" size_category = "S" confidence = "Low" else: estimated_size = "Very Small (<50 sq ft)" size_category = "XS" confidence = "Low" # 6. Room type specific adjustments # Use the room_type parameter passed to the function # Adjust size based on room type expectations if room_type == 'kitchen': if size_category in ['XS', 'S']: estimated_size = "Compact Kitchen (50-80 sq ft)" elif size_category in ['M', 'ML']: estimated_size = "Standard Kitchen (100-150 sq ft)" else: estimated_size = "Large Kitchen (150+ sq ft)" elif room_type == 'bathroom': if size_category in ['XS', 'S']: estimated_size = "Standard Bathroom (40-60 sq ft)" elif size_category in ['M', 'ML']: estimated_size = "Large Bathroom (60-100 sq ft)" else: estimated_size = "Luxury Bathroom (100+ sq ft)" elif room_type == 'bedroom': if size_category in ['XS', 'S']: estimated_size = "Small Bedroom (80-120 sq ft)" elif size_category in ['M', 'ML']: estimated_size = "Standard Bedroom (120-180 sq ft)" else: estimated_size = "Large Bedroom (180+ sq ft)" # 7. Confidence calculation confidence_factors = [] if total_objects >= 5: confidence_factors.append("Multiple objects detected") if len(large_furniture) >= 1: confidence_factors.append("Large furniture present") if object_density > 5: confidence_factors.append("Good object density") if x_variance > 5000 and y_variance > 5000: confidence_factors.append("Good spatial distribution") if len(confidence_factors) >= 3: confidence = "High" elif len(confidence_factors) >= 2: confidence = "Medium" else: confidence = "Low" return { "estimated_size": estimated_size, "size_category": size_category, "confidence": confidence, "confidence_factors": confidence_factors, "size_score": int(size_score), # Convert to Python int "size_factors": size_factors, "object_analysis": { "total_objects": int(total_objects), # Convert to Python int "large_furniture": int(len(large_furniture)), # Convert to Python int "medium_furniture": int(len(medium_furniture)), # Convert to Python int "small_furniture": int(len(small_furniture)), # Convert to Python int "object_density": float(round(object_density, 2)), # Convert to Python float "spatial_variance": { "x_variance": float(round(x_variance, 2)), # Convert to Python float "y_variance": float(round(y_variance, 2)) # Convert to Python float }, "depth_indicator": float(round(depth_indicator, 3)) # Convert to Python float } } except Exception as e: logger.error(f"Error in room size estimation: {str(e)}") return { "estimated_size": "Unable to estimate", "size_category": "Unknown", "confidence": "Low", "confidence_factors": ["Estimation failed"], "size_score": 0, "size_factors": {}, "object_analysis": { "total_objects": 0, "large_furniture": 0, "medium_furniture": 0, "small_furniture": 0, "object_density": 0.0, "spatial_variance": {"x_variance": 0.0, "y_variance": 0.0}, "depth_indicator": 0.0 } } def generate_property_insights(room_classification, quality_analysis, object_detection, image_caption): """Advanced AI-powered property insights generation using dynamic analysis""" try: insights = { "marketing_tips": [], "target_audience": [], "pricing_considerations": [], "improvement_suggestions": [], "market_positioning": {}, "competitive_analysis": {}, "investment_potential": {}, "staging_recommendations": [] } # Extract key data room_type = room_classification.get('room_type', 'unknown') room_confidence = room_classification.get('confidence', 0) quality_score = quality_analysis.get('quality_score', 0) quality_level = quality_analysis.get('quality_level', 'Unknown') object_analysis = object_detection.get('analysis', {}) detected_objects = object_detection.get('objects', []) caption = image_caption.get('caption', '') # 1. Dynamic Marketing Tips Generation marketing_tips = [] # Quality-based marketing tips if quality_score >= 80: marketing_tips.append("Highlight the professional photography quality in listings") marketing_tips.append("Use this image as a primary showcase photo") elif quality_score >= 60: marketing_tips.append("Consider this image for secondary photo positions") else: marketing_tips.append("Use this image sparingly or improve before listing") # Room-specific marketing tips if room_type == 'kitchen': marketing_tips.append("Emphasize modern kitchen features and appliances") marketing_tips.append("Highlight the kitchen as the heart of the home") if object_analysis.get('appliance_count', 0) >= 3: marketing_tips.append("Showcase the fully equipped kitchen") elif room_type == 'bathroom': marketing_tips.append("Focus on cleanliness and modern fixtures") marketing_tips.append("Highlight bathroom luxury and comfort") elif room_type == 'bedroom': marketing_tips.append("Emphasize comfort and relaxation potential") marketing_tips.append("Highlight bedroom size and natural light") elif room_type == 'living room': marketing_tips.append("Showcase entertainment and family gathering spaces") marketing_tips.append("Highlight living room versatility and flow") # Object-based marketing tips furniture_count = object_analysis.get('furniture_count', 0) if furniture_count >= 5: marketing_tips.append("Emphasize the fully furnished and move-in ready aspect") elif furniture_count >= 3: marketing_tips.append("Highlight the well-appointed space") # 2. Advanced Target Audience Analysis target_audience = [] # Room type based targeting if room_type == 'kitchen': target_audience.extend(["Home chefs", "Families", "Entertainment enthusiasts"]) elif room_type == 'bathroom': target_audience.extend(["Luxury seekers", "Families", "Young professionals"]) elif room_type == 'bedroom': target_audience.extend(["Families", "Young professionals", "Students"]) elif room_type == 'living room': target_audience.extend(["Families", "Entertainment lovers", "Social people"]) # Quality-based targeting if quality_score >= 85: target_audience.append("Luxury buyers") elif quality_score >= 70: target_audience.append("Professional buyers") else: target_audience.append("Budget-conscious buyers") # Object-based targeting if object_analysis.get('appliance_count', 0) >= 3: target_audience.append("Modern lifestyle seekers") if object_analysis.get('fixture_count', 0) >= 3: target_audience.append("Quality-conscious buyers") # 3. Dynamic Pricing Considerations pricing_considerations = [] # Quality impact on pricing if quality_score >= 80: pricing_considerations.append("High-quality images can support premium pricing") elif quality_score >= 60: pricing_considerations.append("Standard image quality supports market-rate pricing") else: pricing_considerations.append("Image quality may limit pricing potential") # Room type pricing impact if room_type == 'kitchen': pricing_considerations.append("Kitchen quality significantly impacts property value") if object_analysis.get('appliance_count', 0) >= 3: pricing_considerations.append("Modern appliances justify higher pricing") elif room_type == 'bathroom': pricing_considerations.append("Bathroom luxury can command premium pricing") elif room_type == 'bedroom': pricing_considerations.append("Bedroom appeal affects family buyer pricing") # Object density pricing impact object_density = object_analysis.get('object_density', 0) if object_density > 10: pricing_considerations.append("Rich content suggests well-appointed property") elif object_density < 3: pricing_considerations.append("Sparse content may suggest staging needed") # 4. AI-Powered Improvement Suggestions improvement_suggestions = [] # Technical improvements if quality_score < 70: improvement_suggestions.append("Improve lighting and exposure for better image quality") improvement_suggestions.append("Use professional photography equipment") # Composition improvements composition_balance = object_analysis.get('composition_balance', 0) if composition_balance < 0.4: improvement_suggestions.append("Reposition camera for better composition") improvement_suggestions.append("Follow rule of thirds for better framing") # Content improvements total_objects = object_analysis.get('total_objects', 0) if total_objects < 3: improvement_suggestions.append("Add more furniture or decorative elements") improvement_suggestions.append("Consider professional staging") # Room-specific improvements if room_type == 'kitchen' and object_analysis.get('appliance_count', 0) < 2: improvement_suggestions.append("Highlight kitchen appliances and features") elif room_type == 'bathroom' and object_analysis.get('fixture_count', 0) < 2: improvement_suggestions.append("Showcase bathroom fixtures and amenities") # 5. Advanced Market Positioning Analysis market_positioning = {} # Quality positioning if quality_score >= 85: market_positioning["quality_tier"] = "Premium" market_positioning["positioning_statement"] = "Luxury property with professional presentation" elif quality_score >= 70: market_positioning["quality_tier"] = "Professional" market_positioning["positioning_statement"] = "Well-presented property suitable for discerning buyers" elif quality_score >= 50: market_positioning["quality_tier"] = "Standard" market_positioning["positioning_statement"] = "Standard property presentation" else: market_positioning["quality_tier"] = "Needs Improvement" market_positioning["positioning_statement"] = "Property requires better presentation" # Room type positioning if room_type in ['kitchen', 'bathroom']: market_positioning["focus_area"] = "High-value rooms" market_positioning["key_message"] = f"Showcase {room_type} quality and features" else: market_positioning["focus_area"] = "Living spaces" market_positioning["key_message"] = f"Highlight {room_type} comfort and functionality" # 6. Competitive Analysis competitive_analysis = {} # Quality comparison if quality_score >= 80: competitive_analysis["quality_advantage"] = "Above average" competitive_analysis["differentiation"] = "Professional presentation sets property apart" elif quality_score >= 60: competitive_analysis["quality_advantage"] = "Competitive" competitive_analysis["differentiation"] = "Standard presentation meets market expectations" else: competitive_analysis["quality_advantage"] = "Below average" competitive_analysis["differentiation"] = "Needs improvement to compete effectively" # Content comparison if object_analysis.get('total_objects', 0) >= 8: competitive_analysis["content_advantage"] = "Rich content" competitive_analysis["content_message"] = "Well-appointed space with many features" elif object_analysis.get('total_objects', 0) >= 5: competitive_analysis["content_advantage"] = "Good content" competitive_analysis["content_message"] = "Adequate feature representation" else: competitive_analysis["content_advantage"] = "Limited content" competitive_analysis["content_message"] = "Consider adding more features" # 7. Investment Potential Analysis investment_potential = {} # Quality impact on investment if quality_score >= 80: investment_potential["presentation_value"] = "High" investment_potential["roi_potential"] = "Excellent - professional presentation supports premium pricing" elif quality_score >= 60: investment_potential["presentation_value"] = "Medium" investment_potential["roi_potential"] = "Good - standard presentation supports market pricing" else: investment_potential["presentation_value"] = "Low" investment_potential["roi_potential"] = "Limited - poor presentation may reduce pricing potential" # Room type investment impact if room_type in ['kitchen', 'bathroom']: investment_potential["room_value"] = "High-impact rooms" investment_potential["investment_priority"] = "Focus on these rooms for maximum ROI" else: investment_potential["room_value"] = "Standard rooms" investment_potential["investment_priority"] = "Ensure adequate presentation quality" # 8. Dynamic Staging Recommendations staging_recommendations = [] # Object-based staging if object_analysis.get('furniture_count', 0) < 2: staging_recommendations.append("Add key furniture pieces to define the space") if object_analysis.get('appliance_count', 0) < 2 and room_type == 'kitchen': staging_recommendations.append("Highlight kitchen appliances and modern features") if object_analysis.get('fixture_count', 0) < 2 and room_type == 'bathroom': staging_recommendations.append("Showcase bathroom fixtures and luxury amenities") # Quality-based staging if quality_score < 60: staging_recommendations.append("Improve lighting and staging for better presentation") # Room-specific staging if room_type == 'bedroom': staging_recommendations.append("Create a welcoming and comfortable bedroom atmosphere") elif room_type == 'living room': staging_recommendations.append("Stage for entertainment and family gatherings") # Update insights dictionary insights.update({ "marketing_tips": marketing_tips, "target_audience": list(set(target_audience)), # Remove duplicates "pricing_considerations": pricing_considerations, "improvement_suggestions": improvement_suggestions, "market_positioning": market_positioning, "competitive_analysis": competitive_analysis, "investment_potential": investment_potential, "staging_recommendations": staging_recommendations }) return insights except Exception as e: logger.error(f"Error in generating property insights: {str(e)}") return { "marketing_tips": ["Unable to generate marketing tips"], "target_audience": ["General buyers"], "pricing_considerations": ["Standard market pricing"], "improvement_suggestions": ["Improve image quality and content"], "market_positioning": {"quality_tier": "Unknown"}, "competitive_analysis": {"quality_advantage": "Unknown"}, "investment_potential": {"presentation_value": "Unknown"}, "staging_recommendations": ["Consider professional staging"] } def analyze_scene_with_clip(image, room_type): """Advanced scene understanding using CLIP model""" try: if not clip_processor or not clip_model: return {'scene_concepts': [], 'style_analysis': {}} # Define comprehensive real estate concepts real_estate_concepts = [ # Style concepts "modern design", "traditional style", "contemporary", "luxury", "minimalist", "rustic", "industrial", "scandinavian", "mediterranean", "asian fusion", "art deco", "mid-century modern", # Quality indicators "high-end finishes", "premium materials", "custom details", "architectural features", "natural light", "open floor plan", "high ceilings", "hardwood floors", "granite countertops", # Functionality "functional layout", "efficient design", "storage solutions", "entertainment space", "home office", "flexible space", "outdoor living", "smart home features", # Room-specific concepts "gourmet kitchen", "spa-like bathroom", "master suite", "entertainment room", "dining area", "living space", "bedroom retreat", "home gym", "wine cellar" ] # Process image and text inputs = clip_processor(images=image, text=real_estate_concepts, return_tensors="pt", padding=True) with torch.no_grad(): outputs = clip_model(**inputs) logits_per_image = outputs.logits_per_image probs = logits_per_image.softmax(dim=-1) # Get top matches top_concepts = [] for i, prob in enumerate(probs[0]): if prob > 0.2: # Lower threshold for more concepts top_concepts.append({ "concept": real_estate_concepts[i], "confidence": float(prob) }) # Analyze style patterns style_keywords = ["modern", "traditional", "contemporary", "luxury", "minimalist", "rustic", "industrial"] style_scores = {} for style in style_keywords: style_score = sum(concept["confidence"] for concept in top_concepts if style in concept["concept"].lower()) if style_score > 0: style_scores[style] = style_score # Determine dominant style dominant_style = max(style_scores.items(), key=lambda x: x[1]) if style_scores else ("unknown", 0) return { "scene_concepts": sorted(top_concepts, key=lambda x: x["confidence"], reverse=True)[:10], "style_analysis": { "dominant_style": dominant_style[0], "style_confidence": dominant_style[1], "all_style_scores": style_scores, "quality_indicators": [concept for concept in top_concepts if "quality" in concept["concept"].lower() or "premium" in concept["concept"].lower()], "functionality_indicators": [concept for concept in top_concepts if "functional" in concept["concept"].lower() or "efficient" in concept["concept"].lower()] } } except Exception as e: logger.error(f"CLIP scene analysis failed: {str(e)}") return {'scene_concepts': [], 'style_analysis': {}} def analyze_market_positioning(room_classification, quality_analysis, object_detection, property_assessment): """Advanced market positioning analysis""" try: market_analysis = { "market_tier": "Unknown", "competitive_position": "Unknown", "price_positioning": "Unknown", "target_market": "Unknown", "differentiation_factors": [], "market_opportunities": [], "competitive_advantages": [], "market_risks": [] } # Extract key metrics quality_score = quality_analysis.get('quality_score', 0) overall_score = property_assessment.get('overall_score', 0) room_type = room_classification.get('room_type', 'unknown') room_confidence = room_classification.get('confidence', 0) object_analysis = object_detection.get('analysis', {}) # 1. Market Tier Analysis if overall_score >= 85: market_analysis["market_tier"] = "Luxury" market_analysis["price_positioning"] = "Premium" market_analysis["target_market"] = "High-end buyers, investors" elif overall_score >= 75: market_analysis["market_tier"] = "Premium" market_analysis["price_positioning"] = "Above market" market_analysis["target_market"] = "Professional buyers, families" elif overall_score >= 60: market_analysis["market_tier"] = "Standard" market_analysis["price_positioning"] = "Market rate" market_analysis["target_market"] = "General buyers" else: market_analysis["market_tier"] = "Value" market_analysis["price_positioning"] = "Below market" market_analysis["target_market"] = "Budget-conscious buyers" # 2. Competitive Position Analysis if quality_score >= 80 and room_confidence >= 80: market_analysis["competitive_position"] = "Strong" market_analysis["competitive_advantages"].append("High-quality presentation") market_analysis["competitive_advantages"].append("Clear room identification") elif quality_score >= 60 and room_confidence >= 60: market_analysis["competitive_position"] = "Competitive" market_analysis["competitive_advantages"].append("Good presentation quality") else: market_analysis["competitive_position"] = "Needs improvement" market_analysis["market_risks"].append("Poor presentation may limit appeal") # 3. Room-specific positioning if room_type in ['kitchen', 'bathroom']: appliance_count = object_analysis.get('appliance_count', 0) fixture_count = object_analysis.get('fixture_count', 0) if room_type == 'kitchen' and appliance_count >= 3: market_analysis["differentiation_factors"].append("Fully equipped kitchen") market_analysis["competitive_advantages"].append("Modern kitchen appliances") elif room_type == 'bathroom' and fixture_count >= 2: market_analysis["differentiation_factors"].append("Well-appointed bathroom") market_analysis["competitive_advantages"].append("Quality bathroom fixtures") # 4. Object density analysis object_density = object_analysis.get('object_density', 0) if object_density > 10: market_analysis["differentiation_factors"].append("Rich content and features") market_analysis["competitive_advantages"].append("Well-appointed space") elif object_density < 3: market_analysis["market_risks"].append("Limited content may reduce appeal") # 5. Market opportunities if quality_score < 70: market_analysis["market_opportunities"].append("Improve image quality for better positioning") if room_confidence < 70: market_analysis["market_opportunities"].append("Enhance room type clarity") if object_density < 5: market_analysis["market_opportunities"].append("Add more features and furniture") # 6. Professional grade analysis if property_assessment.get('professional_grade', False): market_analysis["competitive_advantages"].append("Professional-grade presentation") market_analysis["differentiation_factors"].append("High-quality photography") else: market_analysis["market_opportunities"].append("Consider professional photography") return market_analysis except Exception as e: logger.error(f"Market positioning analysis failed: {str(e)}") return { "market_tier": "Unknown", "competitive_position": "Unknown", "price_positioning": "Unknown", "target_market": "Unknown", "differentiation_factors": [], "market_opportunities": [], "competitive_advantages": [], "market_risks": [] } def classify_room_type(image): """Classify room type using the loaded room classifier""" try: if room_classifier is None: return {'room_type': 'unknown', 'confidence': 0} results = room_classifier(image) return { 'room_type': results[0]['label'].lower(), 'confidence': round(results[0]['score'] * 100, 2) } except Exception as e: logger.error(f"Room classification failed: {str(e)}") return {'room_type': 'unknown', 'confidence': 0} @app.route('/') def index(): """Main page for the image analyzer""" return render_template('index.html') @app.route('/analyze', methods=['POST']) def analyze_image(): """Advanced AI-powered property image analysis with comprehensive insights""" try: if 'image' not in request.files: return jsonify({'error': 'No image uploaded'}), 400 file = request.files['image'] if file.filename == '': return jsonify({'error': 'No image selected'}), 400 # Load and validate image try: image = Image.open(file.stream).convert('RGB') # Resize if too large for processing max_size = 1024 if max(image.size) > max_size: image.thumbnail((max_size, max_size), Image.Resampling.LANCZOS) except Exception as e: return jsonify({'error': f'Invalid image format: {str(e)}'}), 400 logger.info(f"Starting advanced analysis for image: {file.filename}") # 1. Advanced Room Classification with Confidence Analysis try: room_results = room_classifier(image) room_classification = { 'room_type': room_results[0]['label'].lower(), 'confidence': round(room_results[0]['score'] * 100, 2), 'all_predictions': [ {'room_type': result['label'].lower(), 'confidence': round(result['score'] * 100, 2)} for result in room_results[:3] ] } logger.info(f"Room classification: {room_classification['room_type']} ({room_classification['confidence']}%)") except Exception as e: logger.error(f"Room classification failed: {e}") room_classification = {'room_type': 'unknown', 'confidence': 0, 'all_predictions': []} # 2. Advanced Image Captioning with Enhanced Descriptions try: caption_results = image_captioner(image, max_new_tokens=50) image_caption = { 'caption': caption_results[0]['generated_text'], 'confidence': 0.85, # BLIP confidence 'enhanced_description': f"A {room_classification['room_type']} featuring {caption_results[0]['generated_text']}" } logger.info(f"Image caption: {image_caption['caption']}") except Exception as e: logger.error(f"Image captioning failed: {e}") image_caption = {'caption': 'Unable to generate caption', 'confidence': 0, 'enhanced_description': ''} # 3. Advanced Object Detection with Multiple Models try: object_detection = detect_objects_advanced(image) logger.info(f"Object detection: {len(object_detection.get('objects', []))} objects detected") except Exception as e: logger.error(f"Object detection failed: {e}") object_detection = {'objects': [], 'analysis': {}} # 4. Advanced Image Quality Analysis with Multiple Metrics try: quality_analysis = analyze_image_quality(image) logger.info(f"Quality analysis: {quality_analysis['quality_level']} ({quality_analysis['quality_score']}/100)") except Exception as e: logger.error(f"Quality analysis failed: {e}") quality_analysis = {'quality_level': 'Analysis Failed', 'quality_score': 0, 'issues': [], 'metrics': {}} # 5. Advanced Room Size Estimation try: room_size = estimate_room_size(image, room_classification['room_type']) logger.info(f"Room size estimation: {room_size['estimated_size']}") except Exception as e: logger.error(f"Room size estimation failed: {e}") room_size = {'estimated_size': 'Unable to estimate', 'confidence': 'Low'} # 6. Advanced Property Assessment with AI Insights try: property_assessment = assess_property_image_quality( room_classification, quality_analysis, object_detection, image_caption ) logger.info(f"Property assessment: {property_assessment['overall_score']}/100") except Exception as e: logger.error(f"Property assessment failed: {e}") property_assessment = {'overall_score': 0, 'strengths': [], 'weaknesses': [], 'recommendations': []} # 7. Advanced Property Insights with Market Analysis try: property_insights = generate_property_insights( room_classification, quality_analysis, object_detection, image_caption ) logger.info("Property insights generated successfully") except Exception as e: logger.error(f"Property insights generation failed: {e}") property_insights = {'marketing_tips': [], 'target_audience': [], 'pricing_considerations': []} # 8. Advanced Scene Understanding with CLIP try: if clip_processor and clip_model: scene_analysis = analyze_scene_with_clip(image, room_classification['room_type']) logger.info("CLIP scene analysis completed") else: scene_analysis = {'scene_concepts': [], 'style_analysis': {}} except Exception as e: logger.error(f"Scene analysis failed: {e}") scene_analysis = {'scene_concepts': [], 'style_analysis': {}} # 9. Advanced Market Positioning Analysis try: market_analysis = analyze_market_positioning( room_classification, quality_analysis, object_detection, property_assessment ) logger.info("Market positioning analysis completed") except Exception as e: logger.error(f"Market positioning analysis failed: {e}") market_analysis = {'market_tier': 'Unknown', 'competitive_position': 'Unknown'} # 10. Generate Comprehensive Report comprehensive_report = { 'analysis_summary': { 'room_type': room_classification['room_type'], 'room_confidence': room_classification['confidence'], 'quality_score': quality_analysis['quality_score'], 'object_count': len(object_detection.get('objects', [])), 'overall_assessment_score': property_assessment['overall_score'], 'professional_grade': property_assessment.get('professional_grade', False) }, 'room_classification': room_classification, 'image_caption': image_caption, 'object_detection': object_detection, 'quality_analysis': quality_analysis, 'room_size_estimation': room_size, 'property_assessment': property_assessment, 'property_insights': property_insights, 'scene_analysis': scene_analysis, 'market_analysis': market_analysis, 'technical_metadata': { 'image_dimensions': image.size, 'analysis_timestamp': datetime.now().isoformat(), 'models_used': ['Room Classification', 'BLIP Captioning', 'DETR Detection', 'Quality Analysis', 'CLIP Scene Understanding'], 'processing_time': 'Real-time' } } # Convert numpy types to Python native types for JSON serialization comprehensive_report = convert_numpy_types(comprehensive_report) logger.info("Advanced analysis completed successfully") return jsonify(comprehensive_report) except Exception as e: logger.error(f"Analysis failed: {str(e)}") return jsonify({'error': f'Analysis failed: {str(e)}'}), 500 @app.route('/health') def health_check(): """Health check endpoint""" return jsonify({ 'status': 'healthy', 'models_loaded': { 'room_classifier': room_classifier is not None, 'image_captioner': image_captioner is not None, 'yolo_model': yolo_model is not None } }) @app.route('/debug') def debug_info(): """Debug endpoint to check application status""" return jsonify({ 'status': 'running', 'port': os.environ.get('PORT', 7860), 'models_loaded': { 'room_classifier': room_classifier is not None, 'image_captioner': image_captioner is not None, 'yolo_model': yolo_model is not None, 'clip_processor': clip_processor is not None, 'clip_model': clip_model is not None }, 'python_version': sys.version, 'torch_available': torch.cuda.is_available() if torch.cuda.is_available() else 'CPU only', 'timestamp': datetime.now().isoformat() }) @app.route('/static/') def static_files(filename): """Serve static files""" return send_from_directory('static', filename) def assess_property_image_quality(room_classification, quality_analysis, object_detection, image_caption): """Advanced AI-powered property image assessment using dynamic analysis""" try: # Initialize assessment components assessment = { "overall_score": 0, "strengths": [], "weaknesses": [], "recommendations": [], "market_appeal": {}, "technical_analysis": {}, "composition_analysis": {}, "professional_grade": False } # 1. Dynamic Room Classification Analysis (0-25 points) room_score = 0 room_confidence = room_classification.get('confidence', 0) room_type = room_classification.get('room_type', 'unknown') # AI-based room type validation if room_confidence > 0.8: room_score = 25 assessment["strengths"].append(f"Clear {room_type} identification with high confidence") elif room_confidence > 0.6: room_score = 20 assessment["strengths"].append(f"Good {room_type} identification") elif room_confidence > 0.4: room_score = 15 assessment["weaknesses"].append(f"Uncertain room type identification") else: room_score = 5 assessment["weaknesses"].append("Poor room type identification") # Cross-validate with object detection object_room_inference = object_detection.get('analysis', {}).get('room_type_inference', {}) if room_type in object_room_inference: object_confidence = object_room_inference[room_type] if object_confidence > 0.5: room_score += 5 # Bonus for consistency assessment["strengths"].append("Object detection confirms room type") else: room_score -= 5 # Penalty for inconsistency assessment["weaknesses"].append("Object detection contradicts room type") # 2. Advanced Quality Analysis (0-30 points) quality_score = 0 quality_metrics = quality_analysis.get('metrics', {}) quality_level = quality_analysis.get('quality_level', 'Unknown') quality_issues = quality_analysis.get('issues', []) # Dynamic quality scoring based on multiple factors base_quality = quality_analysis.get('quality_score', 0) # Technical quality factors brightness_score = 0 brightness_mean = quality_metrics.get('brightness_mean', 128) if 60 <= brightness_mean <= 180: brightness_score = 8 elif 40 <= brightness_mean <= 200: brightness_score = 5 else: brightness_score = 2 contrast_score = 0 contrast = quality_metrics.get('contrast', 0) if contrast > 40: contrast_score = 8 elif contrast > 25: contrast_score = 5 else: contrast_score = 2 sharpness_score = 0 sharpness = quality_metrics.get('sharpness', 0) if sharpness > 80: sharpness_score = 8 elif sharpness > 50: sharpness_score = 5 else: sharpness_score = 2 noise_score = 0 noise_level = quality_metrics.get('noise_level', 0) if noise_level < 0.05: noise_score = 6 elif noise_level < 0.1: noise_score = 4 else: noise_score = 1 quality_score = brightness_score + contrast_score + sharpness_score + noise_score # Add quality issues to weaknesses for issue in quality_issues: assessment["weaknesses"].append(f"Quality: {issue}") # 3. Advanced Object Detection Analysis (0-25 points) object_score = 0 object_analysis = object_detection.get('analysis', {}) detected_objects = object_detection.get('objects', []) # Object richness scoring total_objects = object_analysis.get('total_objects', 0) if total_objects >= 8: object_score += 10 assessment["strengths"].append("Rich object content enhances property appeal") elif total_objects >= 5: object_score += 7 assessment["strengths"].append("Good object variety") elif total_objects >= 3: object_score += 4 else: object_score += 1 assessment["weaknesses"].append("Limited object content") # Object relevance scoring furniture_count = object_analysis.get('furniture_count', 0) appliance_count = object_analysis.get('appliance_count', 0) fixture_count = object_analysis.get('fixture_count', 0) if furniture_count > 0: object_score += 5 if appliance_count > 0: object_score += 5 if fixture_count > 0: object_score += 5 # Composition balance composition_balance = object_analysis.get('composition_balance', 0) if composition_balance > 0.6: object_score += 5 assessment["strengths"].append("Well-balanced object composition") elif composition_balance < 0.3: object_score -= 3 assessment["weaknesses"].append("Poor object distribution") # 4. Dynamic Caption Quality Analysis (0-20 points) caption_score = 0 caption = image_caption.get('caption', '') if caption: # Analyze caption length and content caption_length = len(caption.split()) # Check for real estate keywords real_estate_keywords = ['room', 'kitchen', 'bathroom', 'bedroom', 'living', 'dining', 'modern', 'luxury', 'spacious', 'bright', 'clean', 'furnished'] keyword_count = sum(1 for keyword in real_estate_keywords if keyword.lower() in caption.lower()) if caption_length >= 10 and keyword_count >= 3: caption_score = 20 assessment["strengths"].append("Comprehensive and relevant caption") elif caption_length >= 8 and keyword_count >= 2: caption_score = 15 assessment["strengths"].append("Good descriptive caption") elif caption_length >= 5: caption_score = 10 else: caption_score = 5 assessment["weaknesses"].append("Limited caption description") else: assessment["weaknesses"].append("No caption generated") # 5. Calculate Overall Score with Dynamic Weighting overall_score = room_score + quality_score + object_score + caption_score # Normalize to 100-point scale overall_score = min(100, overall_score) # 6. Advanced Market Appeal Analysis market_appeal = {} # Professional grade determination if overall_score >= 85: assessment["professional_grade"] = True market_appeal["level"] = "Premium" market_appeal["description"] = "Professional-grade image suitable for luxury listings" elif overall_score >= 75: assessment["professional_grade"] = True market_appeal["level"] = "Professional" market_appeal["description"] = "High-quality image for professional listings" elif overall_score >= 60: market_appeal["level"] = "Standard" market_appeal["description"] = "Acceptable quality for standard listings" else: market_appeal["level"] = "Needs Improvement" market_appeal["description"] = "Image requires enhancement before listing" # Target audience analysis if room_type in ['kitchen', 'bathroom'] and quality_score > 20: market_appeal["target_audience"] = "Home buyers, Investors" elif room_type in ['bedroom', 'living room'] and object_score > 15: market_appeal["target_audience"] = "Families, Young professionals" else: market_appeal["target_audience"] = "General buyers" # 7. Dynamic Recommendations Generation recommendations = [] # Quality-based recommendations if brightness_mean < 50: recommendations.append("Increase lighting or use HDR techniques") elif brightness_mean > 200: recommendations.append("Reduce exposure to avoid overexposure") if contrast < 25: recommendations.append("Enhance contrast in post-processing") if sharpness < 50: recommendations.append("Use tripod or image stabilization for sharper photos") if noise_level > 0.1: recommendations.append("Use noise reduction software") # Object-based recommendations if total_objects < 3: recommendations.append("Include more furniture or decorative elements") if composition_balance < 0.4: recommendations.append("Reposition camera for better object distribution") # Room-specific recommendations if room_type == 'kitchen' and appliance_count < 2: recommendations.append("Highlight kitchen appliances and features") elif room_type == 'bathroom' and fixture_count < 2: recommendations.append("Showcase bathroom fixtures and amenities") # Technical recommendations if not assessment["professional_grade"]: recommendations.append("Consider professional photography services") assessment["recommendations"] = recommendations assessment["overall_score"] = overall_score assessment["market_appeal"] = market_appeal # 8. Technical Analysis Summary assessment["technical_analysis"] = { "room_classification_score": room_score, "quality_analysis_score": quality_score, "object_detection_score": object_score, "caption_quality_score": caption_score, "composition_balance": composition_balance, "object_density": object_analysis.get('object_density', 0), "quality_metrics_summary": { "brightness": round(brightness_mean, 1), "contrast": round(contrast, 1), "sharpness": round(sharpness, 1), "noise_level": round(noise_level, 3) } } return assessment except Exception as e: logger.error(f"Error in property assessment: {str(e)}") return { "overall_score": 0, "strengths": [], "weaknesses": ["Assessment failed due to technical error"], "recommendations": ["Please try again with a different image"], "market_appeal": {"level": "Unknown", "description": "Unable to assess"}, "professional_grade": False, "technical_analysis": {} } def estimate_room_size(image, room_type='unknown'): """Advanced AI-powered room size estimation using multiple analysis methods""" try: # Convert PIL image to numpy array img_array = np.array(image) # Get image dimensions height, width = img_array.shape[:2] image_area = height * width # 1. Object-based size estimation object_analysis = detect_objects_advanced(image) detected_objects = object_analysis.get('objects', []) object_analysis_data = object_analysis.get('analysis', {}) # Categorize objects by typical sizes large_furniture = [obj for obj in detected_objects if obj['label'].lower() in ['bed', 'sofa', 'couch', 'dining table', 'kitchen island']] medium_furniture = [obj for obj in detected_objects if obj['label'].lower() in ['chair', 'desk', 'cabinet', 'dresser', 'nightstand']] small_furniture = [obj for obj in detected_objects if obj['label'].lower() in ['lamp', 'plant', 'vase', 'picture frame']] # 2. Object density analysis total_objects = len(detected_objects) object_density = object_analysis_data.get('object_density', 0) # 3. Perspective and depth analysis # Analyze object positioning for depth perception if detected_objects: # Calculate object distribution across image x_positions = [] y_positions = [] object_sizes = [] for obj in detected_objects: bbox = obj['bbox'] x_center = (bbox[0] + bbox[2]) / 2 y_center = (bbox[1] + bbox[3]) / 2 obj_width = bbox[2] - bbox[0] obj_height = bbox[3] - bbox[1] obj_area = obj_width * obj_height x_positions.append(x_center) y_positions.append(y_center) object_sizes.append(obj_area) # Calculate spatial distribution x_variance = float(np.var(x_positions)) if len(x_positions) > 1 else 0.0 y_variance = float(np.var(y_positions)) if len(y_positions) > 1 else 0.0 avg_object_size = float(np.mean(object_sizes)) if object_sizes else 0.0 # Depth perception indicators size_variance = float(np.var(object_sizes)) if len(object_sizes) > 1 else 0.0 depth_indicator = float(size_variance / (avg_object_size + 1e-8)) else: x_variance = y_variance = avg_object_size = depth_indicator = 0.0 # 4. Advanced size estimation algorithm size_score = 0 size_factors = {} # Object count factor (0-30 points) if total_objects >= 10: size_score += 30 size_factors["object_count"] = "Very High" elif total_objects >= 7: size_score += 25 size_factors["object_count"] = "High" elif total_objects >= 5: size_score += 20 size_factors["object_count"] = "Medium-High" elif total_objects >= 3: size_score += 15 size_factors["object_count"] = "Medium" elif total_objects >= 1: size_score += 10 size_factors["object_count"] = "Low" else: size_factors["object_count"] = "Very Low" # Furniture type factor (0-25 points) furniture_score = 0 if len(large_furniture) >= 3: furniture_score = 25 size_factors["furniture_type"] = "Multiple large pieces" elif len(large_furniture) >= 2: furniture_score = 20 size_factors["furniture_type"] = "Several large pieces" elif len(large_furniture) >= 1: furniture_score = 15 size_factors["furniture_type"] = "Some large pieces" elif len(medium_furniture) >= 3: furniture_score = 12 size_factors["furniture_type"] = "Multiple medium pieces" elif len(medium_furniture) >= 1: furniture_score = 8 size_factors["furniture_type"] = "Some medium pieces" else: furniture_score = 5 size_factors["furniture_type"] = "Small pieces only" size_score += furniture_score # Object density factor (0-20 points) if object_density > 15: size_score += 20 size_factors["object_density"] = "Very High" elif object_density > 10: size_score += 15 size_factors["object_density"] = "High" elif object_density > 5: size_score += 10 size_factors["object_density"] = "Medium" elif object_density > 2: size_score += 5 size_factors["object_density"] = "Low" else: size_factors["object_density"] = "Very Low" # Spatial distribution factor (0-15 points) spatial_score = 0 if x_variance > 10000 and y_variance > 10000: spatial_score = 15 size_factors["spatial_distribution"] = "Wide spread" elif x_variance > 5000 or y_variance > 5000: spatial_score = 10 size_factors["spatial_distribution"] = "Moderate spread" elif x_variance > 1000 or y_variance > 1000: spatial_score = 5 size_factors["spatial_distribution"] = "Limited spread" else: size_factors["spatial_distribution"] = "Concentrated" size_score += spatial_score # Depth perception factor (0-10 points) if depth_indicator > 0.5: size_score += 10 size_factors["depth_perception"] = "Strong depth" elif depth_indicator > 0.2: size_score += 7 size_factors["depth_perception"] = "Moderate depth" elif depth_indicator > 0.1: size_score += 4 size_factors["depth_perception"] = "Limited depth" else: size_factors["depth_perception"] = "Flat perspective" # 5. Dynamic size classification if size_score >= 80: estimated_size = "Very Large (300+ sq ft)" size_category = "XL" confidence = "High" elif size_score >= 65: estimated_size = "Large (200-300 sq ft)" size_category = "L" confidence = "High" elif size_score >= 50: estimated_size = "Medium-Large (150-200 sq ft)" size_category = "ML" confidence = "Medium" elif size_score >= 35: estimated_size = "Medium (100-150 sq ft)" size_category = "M" confidence = "Medium" elif size_score >= 20: estimated_size = "Small-Medium (80-100 sq ft)" size_category = "SM" confidence = "Medium" elif size_score >= 10: estimated_size = "Small (50-80 sq ft)" size_category = "S" confidence = "Low" else: estimated_size = "Very Small (<50 sq ft)" size_category = "XS" confidence = "Low" # 6. Room type specific adjustments # Use the room_type parameter passed to the function # Adjust size based on room type expectations if room_type == 'kitchen': if size_category in ['XS', 'S']: estimated_size = "Compact Kitchen (50-80 sq ft)" elif size_category in ['M', 'ML']: estimated_size = "Standard Kitchen (100-150 sq ft)" else: estimated_size = "Large Kitchen (150+ sq ft)" elif room_type == 'bathroom': if size_category in ['XS', 'S']: estimated_size = "Standard Bathroom (40-60 sq ft)" elif size_category in ['M', 'ML']: estimated_size = "Large Bathroom (60-100 sq ft)" else: estimated_size = "Luxury Bathroom (100+ sq ft)" elif room_type == 'bedroom': if size_category in ['XS', 'S']: estimated_size = "Small Bedroom (80-120 sq ft)" elif size_category in ['M', 'ML']: estimated_size = "Standard Bedroom (120-180 sq ft)" else: estimated_size = "Large Bedroom (180+ sq ft)" # 7. Confidence calculation confidence_factors = [] if total_objects >= 5: confidence_factors.append("Multiple objects detected") if len(large_furniture) >= 1: confidence_factors.append("Large furniture present") if object_density > 5: confidence_factors.append("Good object density") if x_variance > 5000 and y_variance > 5000: confidence_factors.append("Good spatial distribution") if len(confidence_factors) >= 3: confidence = "High" elif len(confidence_factors) >= 2: confidence = "Medium" else: confidence = "Low" return { "estimated_size": estimated_size, "size_category": size_category, "confidence": confidence, "confidence_factors": confidence_factors, "size_score": int(size_score), # Convert to Python int "size_factors": size_factors, "object_analysis": { "total_objects": int(total_objects), # Convert to Python int "large_furniture": int(len(large_furniture)), # Convert to Python int "medium_furniture": int(len(medium_furniture)), # Convert to Python int "small_furniture": int(len(small_furniture)), # Convert to Python int "object_density": float(round(object_density, 2)), # Convert to Python float "spatial_variance": { "x_variance": float(round(x_variance, 2)), # Convert to Python float "y_variance": float(round(y_variance, 2)) # Convert to Python float }, "depth_indicator": float(round(depth_indicator, 3)) # Convert to Python float } } except Exception as e: logger.error(f"Error in room size estimation: {str(e)}") return { "estimated_size": "Unable to estimate", "size_category": "Unknown", "confidence": "Low", "confidence_factors": ["Estimation failed"], "size_score": 0, "size_factors": {}, "object_analysis": { "total_objects": 0, "large_furniture": 0, "medium_furniture": 0, "small_furniture": 0, "object_density": 0.0, "spatial_variance": {"x_variance": 0.0, "y_variance": 0.0}, "depth_indicator": 0.0 } } def generate_property_insights(room_classification, quality_analysis, object_detection, image_caption): """Advanced AI-powered property insights generation using dynamic analysis""" try: insights = { "marketing_tips": [], "target_audience": [], "pricing_considerations": [], "improvement_suggestions": [], "market_positioning": {}, "competitive_analysis": {}, "investment_potential": {}, "staging_recommendations": [] } # Extract key data room_type = room_classification.get('room_type', 'unknown') room_confidence = room_classification.get('confidence', 0) quality_score = quality_analysis.get('quality_score', 0) quality_level = quality_analysis.get('quality_level', 'Unknown') object_analysis = object_detection.get('analysis', {}) detected_objects = object_detection.get('objects', []) caption = image_caption.get('caption', '') # 1. Dynamic Marketing Tips Generation marketing_tips = [] # Quality-based marketing tips if quality_score >= 80: marketing_tips.append("Highlight the professional photography quality in listings") marketing_tips.append("Use this image as a primary showcase photo") elif quality_score >= 60: marketing_tips.append("Consider this image for secondary photo positions") else: marketing_tips.append("Use this image sparingly or improve before listing") # Room-specific marketing tips if room_type == 'kitchen': marketing_tips.append("Emphasize modern kitchen features and appliances") marketing_tips.append("Highlight the kitchen as the heart of the home") if object_analysis.get('appliance_count', 0) >= 3: marketing_tips.append("Showcase the fully equipped kitchen") elif room_type == 'bathroom': marketing_tips.append("Focus on cleanliness and modern fixtures") marketing_tips.append("Highlight bathroom luxury and comfort") elif room_type == 'bedroom': marketing_tips.append("Emphasize comfort and relaxation potential") marketing_tips.append("Highlight bedroom size and natural light") elif room_type == 'living room': marketing_tips.append("Showcase entertainment and family gathering spaces") marketing_tips.append("Highlight living room versatility and flow") # Object-based marketing tips furniture_count = object_analysis.get('furniture_count', 0) if furniture_count >= 5: marketing_tips.append("Emphasize the fully furnished and move-in ready aspect") elif furniture_count >= 3: marketing_tips.append("Highlight the well-appointed space") # 2. Advanced Target Audience Analysis target_audience = [] # Room type based targeting if room_type == 'kitchen': target_audience.extend(["Home chefs", "Families", "Entertainment enthusiasts"]) elif room_type == 'bathroom': target_audience.extend(["Luxury seekers", "Families", "Young professionals"]) elif room_type == 'bedroom': target_audience.extend(["Families", "Young professionals", "Students"]) elif room_type == 'living room': target_audience.extend(["Families", "Entertainment lovers", "Social people"]) # Quality-based targeting if quality_score >= 85: target_audience.append("Luxury buyers") elif quality_score >= 70: target_audience.append("Professional buyers") else: target_audience.append("Budget-conscious buyers") # Object-based targeting if object_analysis.get('appliance_count', 0) >= 3: target_audience.append("Modern lifestyle seekers") if object_analysis.get('fixture_count', 0) >= 3: target_audience.append("Quality-conscious buyers") # 3. Dynamic Pricing Considerations pricing_considerations = [] # Quality impact on pricing if quality_score >= 80: pricing_considerations.append("High-quality images can support premium pricing") elif quality_score >= 60: pricing_considerations.append("Standard image quality supports market-rate pricing") else: pricing_considerations.append("Image quality may limit pricing potential") # Room type pricing impact if room_type == 'kitchen': pricing_considerations.append("Kitchen quality significantly impacts property value") if object_analysis.get('appliance_count', 0) >= 3: pricing_considerations.append("Modern appliances justify higher pricing") elif room_type == 'bathroom': pricing_considerations.append("Bathroom luxury can command premium pricing") elif room_type == 'bedroom': pricing_considerations.append("Bedroom appeal affects family buyer pricing") # Object density pricing impact object_density = object_analysis.get('object_density', 0) if object_density > 10: pricing_considerations.append("Rich content suggests well-appointed property") elif object_density < 3: pricing_considerations.append("Sparse content may suggest staging needed") # 4. AI-Powered Improvement Suggestions improvement_suggestions = [] # Technical improvements if quality_score < 70: improvement_suggestions.append("Improve lighting and exposure for better image quality") improvement_suggestions.append("Use professional photography equipment") # Composition improvements composition_balance = object_analysis.get('composition_balance', 0) if composition_balance < 0.4: improvement_suggestions.append("Reposition camera for better composition") improvement_suggestions.append("Follow rule of thirds for better framing") # Content improvements total_objects = object_analysis.get('total_objects', 0) if total_objects < 3: improvement_suggestions.append("Add more furniture or decorative elements") improvement_suggestions.append("Consider professional staging") # Room-specific improvements if room_type == 'kitchen' and object_analysis.get('appliance_count', 0) < 2: improvement_suggestions.append("Highlight kitchen appliances and features") elif room_type == 'bathroom' and object_analysis.get('fixture_count', 0) < 2: improvement_suggestions.append("Showcase bathroom fixtures and amenities") # 5. Advanced Market Positioning Analysis market_positioning = {} # Quality positioning if quality_score >= 85: market_positioning["quality_tier"] = "Premium" market_positioning["positioning_statement"] = "Luxury property with professional presentation" elif quality_score >= 70: market_positioning["quality_tier"] = "Professional" market_positioning["positioning_statement"] = "Well-presented property suitable for discerning buyers" elif quality_score >= 50: market_positioning["quality_tier"] = "Standard" market_positioning["positioning_statement"] = "Standard property presentation" else: market_positioning["quality_tier"] = "Needs Improvement" market_positioning["positioning_statement"] = "Property requires better presentation" # Room type positioning if room_type in ['kitchen', 'bathroom']: market_positioning["focus_area"] = "High-value rooms" market_positioning["key_message"] = f"Showcase {room_type} quality and features" else: market_positioning["focus_area"] = "Living spaces" market_positioning["key_message"] = f"Highlight {room_type} comfort and functionality" # 6. Competitive Analysis competitive_analysis = {} # Quality comparison if quality_score >= 80: competitive_analysis["quality_advantage"] = "Above average" competitive_analysis["differentiation"] = "Professional presentation sets property apart" elif quality_score >= 60: competitive_analysis["quality_advantage"] = "Competitive" competitive_analysis["differentiation"] = "Standard presentation meets market expectations" else: competitive_analysis["quality_advantage"] = "Below average" competitive_analysis["differentiation"] = "Needs improvement to compete effectively" # Content comparison if object_analysis.get('total_objects', 0) >= 8: competitive_analysis["content_advantage"] = "Rich content" competitive_analysis["content_message"] = "Well-appointed space with many features" elif object_analysis.get('total_objects', 0) >= 5: competitive_analysis["content_advantage"] = "Good content" competitive_analysis["content_message"] = "Adequate feature representation" else: competitive_analysis["content_advantage"] = "Limited content" competitive_analysis["content_message"] = "Consider adding more features" # 7. Investment Potential Analysis investment_potential = {} # Quality impact on investment if quality_score >= 80: investment_potential["presentation_value"] = "High" investment_potential["roi_potential"] = "Excellent - professional presentation supports premium pricing" elif quality_score >= 60: investment_potential["presentation_value"] = "Medium" investment_potential["roi_potential"] = "Good - standard presentation supports market pricing" else: investment_potential["presentation_value"] = "Low" investment_potential["roi_potential"] = "Limited - poor presentation may reduce pricing potential" # Room type investment impact if room_type in ['kitchen', 'bathroom']: investment_potential["room_value"] = "High-impact rooms" investment_potential["investment_priority"] = "Focus on these rooms for maximum ROI" else: investment_potential["room_value"] = "Standard rooms" investment_potential["investment_priority"] = "Ensure adequate presentation quality" # 8. Dynamic Staging Recommendations staging_recommendations = [] # Object-based staging if object_analysis.get('furniture_count', 0) < 2: staging_recommendations.append("Add key furniture pieces to define the space") if object_analysis.get('appliance_count', 0) < 2 and room_type == 'kitchen': staging_recommendations.append("Highlight kitchen appliances and modern features") if object_analysis.get('fixture_count', 0) < 2 and room_type == 'bathroom': staging_recommendations.append("Showcase bathroom fixtures and luxury amenities") # Quality-based staging if quality_score < 60: staging_recommendations.append("Improve lighting and staging for better presentation") # Room-specific staging if room_type == 'bedroom': staging_recommendations.append("Create a welcoming and comfortable bedroom atmosphere") elif room_type == 'living room': staging_recommendations.append("Stage for entertainment and family gatherings") # Update insights dictionary insights.update({ "marketing_tips": marketing_tips, "target_audience": list(set(target_audience)), # Remove duplicates "pricing_considerations": pricing_considerations, "improvement_suggestions": improvement_suggestions, "market_positioning": market_positioning, "competitive_analysis": competitive_analysis, "investment_potential": investment_potential, "staging_recommendations": staging_recommendations }) return insights except Exception as e: logger.error(f"Error in generating property insights: {str(e)}") return { "marketing_tips": ["Unable to generate marketing tips"], "target_audience": ["General buyers"], "pricing_considerations": ["Standard market pricing"], "improvement_suggestions": ["Improve image quality and content"], "market_positioning": {"quality_tier": "Unknown"}, "competitive_analysis": {"quality_advantage": "Unknown"}, "investment_potential": {"presentation_value": "Unknown"}, "staging_recommendations": ["Consider professional staging"] } def analyze_scene_with_clip(image, room_type): """Advanced scene understanding using CLIP model""" try: if not clip_processor or not clip_model: return {'scene_concepts': [], 'style_analysis': {}} # Define comprehensive real estate concepts real_estate_concepts = [ # Style concepts "modern design", "traditional style", "contemporary", "luxury", "minimalist", "rustic", "industrial", "scandinavian", "mediterranean", "asian fusion", "art deco", "mid-century modern", # Quality indicators "high-end finishes", "premium materials", "custom details", "architectural features", "natural light", "open floor plan", "high ceilings", "hardwood floors", "granite countertops", # Functionality "functional layout", "efficient design", "storage solutions", "entertainment space", "home office", "flexible space", "outdoor living", "smart home features", # Room-specific concepts "gourmet kitchen", "spa-like bathroom", "master suite", "entertainment room", "dining area", "living space", "bedroom retreat", "home gym", "wine cellar" ] # Process image and text inputs = clip_processor(images=image, text=real_estate_concepts, return_tensors="pt", padding=True) with torch.no_grad(): outputs = clip_model(**inputs) logits_per_image = outputs.logits_per_image probs = logits_per_image.softmax(dim=-1) # Get top matches top_concepts = [] for i, prob in enumerate(probs[0]): if prob > 0.2: # Lower threshold for more concepts top_concepts.append({ "concept": real_estate_concepts[i], "confidence": float(prob) }) # Analyze style patterns style_keywords = ["modern", "traditional", "contemporary", "luxury", "minimalist", "rustic", "industrial"] style_scores = {} for style in style_keywords: style_score = sum(concept["confidence"] for concept in top_concepts if style in concept["concept"].lower()) if style_score > 0: style_scores[style] = style_score # Determine dominant style dominant_style = max(style_scores.items(), key=lambda x: x[1]) if style_scores else ("unknown", 0) return { "scene_concepts": sorted(top_concepts, key=lambda x: x["confidence"], reverse=True)[:10], "style_analysis": { "dominant_style": dominant_style[0], "style_confidence": dominant_style[1], "all_style_scores": style_scores, "quality_indicators": [concept for concept in top_concepts if "quality" in concept["concept"].lower() or "premium" in concept["concept"].lower()], "functionality_indicators": [concept for concept in top_concepts if "functional" in concept["concept"].lower() or "efficient" in concept["concept"].lower()] } } except Exception as e: logger.error(f"CLIP scene analysis failed: {str(e)}") return {'scene_concepts': [], 'style_analysis': {}} def analyze_market_positioning(room_classification, quality_analysis, object_detection, property_assessment): """Advanced market positioning analysis""" try: market_analysis = { "market_tier": "Unknown", "competitive_position": "Unknown", "price_positioning": "Unknown", "target_market": "Unknown", "differentiation_factors": [], "market_opportunities": [], "competitive_advantages": [], "market_risks": [] } # Extract key metrics quality_score = quality_analysis.get('quality_score', 0) overall_score = property_assessment.get('overall_score', 0) room_type = room_classification.get('room_type', 'unknown') room_confidence = room_classification.get('confidence', 0) object_analysis = object_detection.get('analysis', {}) # 1. Market Tier Analysis if overall_score >= 85: market_analysis["market_tier"] = "Luxury" market_analysis["price_positioning"] = "Premium" market_analysis["target_market"] = "High-end buyers, investors" elif overall_score >= 75: market_analysis["market_tier"] = "Premium" market_analysis["price_positioning"] = "Above market" market_analysis["target_market"] = "Professional buyers, families" elif overall_score >= 60: market_analysis["market_tier"] = "Standard" market_analysis["price_positioning"] = "Market rate" market_analysis["target_market"] = "General buyers" else: market_analysis["market_tier"] = "Value" market_analysis["price_positioning"] = "Below market" market_analysis["target_market"] = "Budget-conscious buyers" # 2. Competitive Position Analysis if quality_score >= 80 and room_confidence >= 80: market_analysis["competitive_position"] = "Strong" market_analysis["competitive_advantages"].append("High-quality presentation") market_analysis["competitive_advantages"].append("Clear room identification") elif quality_score >= 60 and room_confidence >= 60: market_analysis["competitive_position"] = "Competitive" market_analysis["competitive_advantages"].append("Good presentation quality") else: market_analysis["competitive_position"] = "Needs improvement" market_analysis["market_risks"].append("Poor presentation may limit appeal") # 3. Room-specific positioning if room_type in ['kitchen', 'bathroom']: appliance_count = object_analysis.get('appliance_count', 0) fixture_count = object_analysis.get('fixture_count', 0) if room_type == 'kitchen' and appliance_count >= 3: market_analysis["differentiation_factors"].append("Fully equipped kitchen") market_analysis["competitive_advantages"].append("Modern kitchen appliances") elif room_type == 'bathroom' and fixture_count >= 2: market_analysis["differentiation_factors"].append("Well-appointed bathroom") market_analysis["competitive_advantages"].append("Quality bathroom fixtures") # 4. Object density analysis object_density = object_analysis.get('object_density', 0) if object_density > 10: market_analysis["differentiation_factors"].append("Rich content and features") market_analysis["competitive_advantages"].append("Well-appointed space") elif object_density < 3: market_analysis["market_risks"].append("Limited content may reduce appeal") # 5. Market opportunities if quality_score < 70: market_analysis["market_opportunities"].append("Improve image quality for better positioning") if room_confidence < 70: market_analysis["market_opportunities"].append("Enhance room type clarity") if object_density < 5: market_analysis["market_opportunities"].append("Add more features and furniture") # 6. Professional grade analysis if property_assessment.get('professional_grade', False): market_analysis["competitive_advantages"].append("Professional-grade presentation") market_analysis["differentiation_factors"].append("High-quality photography") else: market_analysis["market_opportunities"].append("Consider professional photography") return market_analysis except Exception as e: logger.error(f"Market positioning analysis failed: {str(e)}") return { "market_tier": "Unknown", "competitive_position": "Unknown", "price_positioning": "Unknown", "target_market": "Unknown", "differentiation_factors": [], "market_opportunities": [], "competitive_advantages": [], "market_risks": [] } def classify_room_type(image): """Classify room type using the loaded room classifier""" try: if room_classifier is None: return {'room_type': 'unknown', 'confidence': 0} results = room_classifier(image) return { 'room_type': results[0]['label'].lower(), 'confidence': round(results[0]['score'] * 100, 2) } except Exception as e: logger.error(f"Room classification failed: {str(e)}") return {'room_type': 'unknown', 'confidence': 0} if __name__ == '__main__': # Load models on startup logger.info("Starting Real Estate Image Analyzer...") load_models() # Get port from environment variable or use default port = int(os.environ.get('PORT', 7860)) logger.info(f"Using port: {port}") # Kill any existing processes on the port (just in case) kill_process_on_port(port) time.sleep(1) logger.info(f"Starting Flask app on port {port}") logger.info(f"Access your application at: http://localhost:{port}") # Start Flask app app.run(port=port, debug=False, host='0.0.0.0')