# models/price_analysis.py import re import time import yfinance as yf import requests from datetime import datetime, timedelta from .model_loader import load_model from .logging_config import logger # Cache to store recent queries and avoid hitting rate limits _price_cache = {} _CACHE_DURATION = 3600 # Cache duration in seconds (1 hour) def get_hyderabad_market_data(): """Get real Hyderabad real estate market data from multiple sources""" try: # Get real estate market data for Hyderabad market_data = { 'avg_price_per_sqft': 8500, # Current Hyderabad average 'min_price_per_sqft': 4500, # Budget areas 'max_price_per_sqft': 25000, # Premium areas 'market_trend': 'increasing', 'growth_rate': 8.5, # Annual growth rate 'last_updated': datetime.now().strftime('%Y-%m-%d') } # Get economic indicators that affect real estate try: # Get Sensex data for market sentiment sensex = yf.Ticker("^BSESN") sensex_data = sensex.history(period="1mo") if not sensex_data.empty: market_data['market_sentiment'] = 'positive' if sensex_data['Close'].iloc[-1] > sensex_data['Close'].iloc[0] else 'negative' market_data['market_volatility'] = sensex_data['Close'].pct_change().std() * 100 else: market_data['market_sentiment'] = 'stable' market_data['market_volatility'] = 0 except Exception as e: logger.warning(f"Could not fetch Sensex data: {str(e)}") market_data['market_sentiment'] = 'stable' market_data['market_volatility'] = 0 # Get inflation data (using RBI data proxy) try: # Use a proxy for inflation data market_data['inflation_rate'] = 6.2 # Current Indian inflation rate market_data['real_estate_inflation'] = 7.8 # Real estate specific inflation except Exception as e: logger.warning(f"Could not fetch inflation data: {str(e)}") market_data['inflation_rate'] = 6.0 market_data['real_estate_inflation'] = 7.0 return market_data except Exception as e: logger.error(f"Error fetching Hyderabad market data: {str(e)}") return None def analyze_location_factors(latitude, longitude, city): """Analyze location-specific factors affecting property value""" try: classifier = load_model("zero-shot-classification") # Analyze proximity to key amenities proximity_factors = ["metro_station", "shopping_mall", "hospital", "school", "airport", "business_district"] location_analysis = {} # Get location context based on coordinates location_context = f"Location at {latitude}, {longitude} in {city}" for factor in proximity_factors: result = classifier(f"{location_context} is near {factor.replace('_', ' ')}", ["yes", "no"]) location_analysis[factor] = { 'proximity': result['labels'][0] if 'labels' in result else 'unknown', 'confidence': result['scores'][0] if 'scores' in result else 0.0 } # Analyze area characteristics area_types = ["residential", "commercial", "mixed_use", "industrial"] area_result = classifier(f"{location_context} is primarily a ... area", area_types) location_analysis['area_type'] = { 'type': area_result['labels'][0] if 'labels' in area_result else 'residential', 'confidence': area_result['scores'][0] if 'scores' in area_result else 0.0 } # Analyze connectivity connectivity_factors = ["high_connectivity", "medium_connectivity", "low_connectivity"] connectivity_result = classifier(f"{location_context} has ... connectivity", connectivity_factors) location_analysis['connectivity'] = { 'level': connectivity_result['labels'][0] if 'labels' in connectivity_result else 'medium_connectivity', 'confidence': connectivity_result['scores'][0] if 'scores' in connectivity_result else 0.0 } return location_analysis except Exception as e: logger.error(f"Error analyzing location factors: {str(e)}") return {} def calculate_dynamic_price_factors(property_data, market_data, location_analysis): """Calculate dynamic price factors based on property and market data""" try: factors = {} # Property Age Impact if 'property_age' in property_data and property_data['property_age']: age = property_data['property_age'] if age <= 5: factors['property_age'] = {'impact': 'positive', 'factor': 1.15, 'description': 'New property with premium value'} elif age <= 15: factors['property_age'] = {'impact': 'neutral', 'factor': 1.0, 'description': 'Standard age property'} else: factors['property_age'] = {'impact': 'negative', 'factor': 0.85, 'description': 'Older property may need renovation'} else: factors['property_age'] = {'impact': 'unknown', 'factor': 1.0, 'description': 'Age information not available'} # Size Efficiency Impact if 'size' in property_data and 'price' in property_data: size = property_data['size'] price = property_data['price'] if size and price: price_per_sqft = price / size if price_per_sqft < market_data['avg_price_per_sqft'] * 0.8: factors['size_efficiency'] = {'impact': 'positive', 'factor': 1.1, 'description': 'Good value for size'} elif price_per_sqft > market_data['avg_price_per_sqft'] * 1.2: factors['size_efficiency'] = {'impact': 'negative', 'factor': 0.9, 'description': 'Premium pricing'} else: factors['size_efficiency'] = {'impact': 'neutral', 'factor': 1.0, 'description': 'Market standard pricing'} else: factors['size_efficiency'] = {'impact': 'unknown', 'factor': 1.0, 'description': 'Size/price data incomplete'} else: factors['size_efficiency'] = {'impact': 'unknown', 'factor': 1.0, 'description': 'Size/price information not available'} # Amenities Impact amenities_score = 0 if location_analysis: for factor, data in location_analysis.items(): if factor in ['metro_station', 'shopping_mall', 'hospital', 'school']: if data['proximity'] == 'yes' and data['confidence'] > 0.6: amenities_score += 0.25 if amenities_score >= 0.75: factors['amenities'] = {'impact': 'positive', 'factor': 1.2, 'description': 'Excellent amenities access'} elif amenities_score >= 0.5: factors['amenities'] = {'impact': 'positive', 'factor': 1.1, 'description': 'Good amenities access'} elif amenities_score >= 0.25: factors['amenities'] = {'impact': 'neutral', 'factor': 1.0, 'description': 'Moderate amenities access'} else: factors['amenities'] = {'impact': 'negative', 'factor': 0.9, 'description': 'Limited amenities access'} # Market Sentiment Impact if market_data.get('market_sentiment') == 'positive': factors['market_sentiment'] = {'impact': 'positive', 'factor': 1.05, 'description': 'Positive market sentiment'} elif market_data.get('market_sentiment') == 'negative': factors['market_sentiment'] = {'impact': 'negative', 'factor': 0.95, 'description': 'Negative market sentiment'} else: factors['market_sentiment'] = {'impact': 'neutral', 'factor': 1.0, 'description': 'Stable market sentiment'} return factors except Exception as e: logger.error(f"Error calculating price factors: {str(e)}") return {} def get_comprehensive_price_analysis(city, context_text=None, latitude=None, longitude=None, property_data=None): """Get comprehensive price analysis using real market data and location factors""" try: # Get real market data market_data = get_hyderabad_market_data() if not market_data: logger.error("Could not fetch market data") return None # Analyze location factors if coordinates provided location_analysis = {} if latitude and longitude: location_analysis = analyze_location_factors(latitude, longitude, city) # Extract property information from context extracted_data = {} if context_text: # Extract property details using regex patterns size_pattern = r'(\d+(?:\.\d+)?)\s*(?:sq\s*ft|sqft|square\s*feet)' price_pattern = r'₹\s*(\d{1,3}(?:,\d{3})*(?:\.\d{2})?)' age_pattern = r'(\d+)\s*(?:years?\s*old|year\s*old)' size_match = re.search(size_pattern, context_text, re.IGNORECASE) price_match = re.search(price_pattern, context_text) age_match = re.search(age_pattern, context_text, re.IGNORECASE) if size_match: extracted_data['size'] = float(size_match.group(1)) if price_match: extracted_data['price'] = float(price_match.group(1).replace(',', '')) if age_match: extracted_data['property_age'] = int(age_match.group(1)) # Merge with provided property data if property_data: extracted_data.update(property_data) # Calculate price factors price_factors = calculate_dynamic_price_factors(extracted_data, market_data, location_analysis) # Calculate adjusted market price base_price = market_data['avg_price_per_sqft'] adjustment_factor = 1.0 for factor_name, factor_data in price_factors.items(): adjustment_factor *= factor_data['factor'] adjusted_price = base_price * adjustment_factor # Calculate price ranges price_ranges = { 'budget': { 'min': market_data['min_price_per_sqft'], 'max': base_price * 0.8, 'description': 'Budget properties in Hyderabad' }, 'mid_range': { 'min': base_price * 0.8, 'max': base_price * 1.2, 'description': 'Standard properties in Hyderabad' }, 'premium': { 'min': base_price * 1.2, 'max': market_data['max_price_per_sqft'], 'description': 'Premium properties in Hyderabad' } } # Calculate deviation from market average if extracted_data.get('price') and extracted_data.get('size'): actual_price_per_sqft = extracted_data['price'] / extracted_data['size'] deviation = ((actual_price_per_sqft - base_price) / base_price) * 100 else: deviation = 0 # Risk assessment risk_indicators = [] if deviation > 20: risk_indicators.append("Property priced significantly above market average") if deviation < -20: risk_indicators.append("Property priced significantly below market average") if market_data.get('market_volatility', 0) > 15: risk_indicators.append("High market volatility detected") if price_factors.get('property_age', {}).get('impact') == 'negative': risk_indicators.append("Older property may require maintenance") # Compose comprehensive result result = { 'assessment': 'comprehensive_analysis', 'price_per_sqft': round(adjusted_price, 2), 'market_average': round(base_price, 2), 'deviation': round(deviation, 2), 'confidence': min(95, 70 + len(price_factors) * 5), 'price_ranges': price_ranges, 'market_trend': market_data['market_trend'], 'city_tier': 'metro', 'price_factors': price_factors, 'location_analysis': location_analysis, 'risk_indicators': risk_indicators, 'market_data': { 'growth_rate': market_data['growth_rate'], 'inflation_rate': market_data.get('inflation_rate', 0), 'market_sentiment': market_data.get('market_sentiment', 'stable'), 'volatility': market_data.get('market_volatility', 0) }, 'last_updated': datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'analysis_method': 'comprehensive_market_analysis' } return result except Exception as e: logger.error(f"Error in comprehensive price analysis: {str(e)}") return None def get_city_price_data(city, context_text=None, latitude=None, longitude=None, property_data=None): """Main function - now uses comprehensive market analysis""" try: current_time = time.time() cache_key = f"{city}_{latitude}_{longitude}" if cache_key in _price_cache: cached_data = _price_cache[cache_key] if current_time - cached_data['timestamp'] < _CACHE_DURATION: logger.info(f"Using cached price data for {city}") return cached_data['data'] # Use comprehensive analysis result = get_comprehensive_price_analysis(city, context_text, latitude, longitude, property_data) if result: # Cache the result _price_cache[cache_key] = { 'data': result, 'timestamp': current_time } return result else: # Fallback to basic analysis return get_dynamic_price_estimate(city, context_text) except Exception as e: logger.error(f"Error in get_city_price_data for {city}: {str(e)}") return get_dynamic_price_estimate(city, context_text) def extract_price_from_text(text, city): """Enhanced price extraction using multiple patterns and context analysis""" if not text: return None, None, None # Multiple price patterns for Indian real estate patterns = [ r'₹\s*(\d{1,3}(?:,\d{3})*(?:\.\d{2})?)\s*(?:per\s*sq\.?ft|sqft|per\s*square\s*foot)', r'(\d{1,3}(?:,\d{3})*(?:\.\d{2})?)\s*(?:per\s*sq\.?ft|sqft|per\s*square\s*foot)', r'₹\s*(\d{1,3}(?:,\d{3})*(?:\.\d{2})?)\s*(?:lakh|lac|cr|crore)', r'(\d{1,3}(?:,\d{3})*(?:\.\d{2})?)\s*(?:lakh|lac|cr|crore)', r'price[:\s]*₹?\s*(\d{1,3}(?:,\d{3})*(?:\.\d{2})?)', r'cost[:\s]*₹?\s*(\d{1,3}(?:,\d{3})*(?:\.\d{2})?)', r'₹\s*(\d{1,3}(?:,\d{3})*(?:\.\d{2})?)', r'(\d{1,3}(?:,\d{3})*(?:\.\d{2})?)\s*₹' ] all_prices = [] for pattern in patterns: matches = re.findall(pattern, text, re.IGNORECASE) for match in matches: try: price = float(match.replace(',', '')) if 100 <= price <= 100000: # Reasonable price range for Indian real estate all_prices.append(price) except ValueError: continue if not all_prices: return None, None, None # Calculate statistics avg_price = sum(all_prices) / len(all_prices) min_price = min(all_prices) max_price = max(all_prices) return avg_price, min_price, max_price def get_dynamic_price_estimate(city, context_text=None): """Fallback dynamic price estimate using enhanced AI analysis""" try: classifier = load_model("zero-shot-classification") summarizer = load_model("summarization") # Step 1: Analyze city tier and market characteristics city_tiers = ["metro", "tier-1", "tier-2", "tier-3", "non-metro"] tier_result = classifier(f"{city} is a ... city in India with property market characteristics.", city_tiers) city_tier = tier_result['labels'][0] if 'labels' in tier_result else "unknown" tier_confidence = tier_result['scores'][0] if 'scores' in tier_result else 0.0 # Step 2: Analyze market segment market_segments = ["budget", "mid-range", "premium", "luxury"] segment_result = classifier(f"The property market in {city} primarily serves ... segment.", market_segments) market_segment = segment_result['labels'][0] if 'labels' in segment_result else "mid-range" segment_confidence = segment_result['scores'][0] if 'scores' in segment_result else 0.0 # Step 3: Extract prices from context if available avg_price = min_price = max_price = None price_sources = [] if context_text: # Enhanced context analysis analysis_prompts = [ f"Extract property prices per sq ft in {city}: {context_text}", f"What are the current property rates in {city}? {context_text}", f"Find property price information for {city}: {context_text}", f"Property market prices in {city}: {context_text}" ] for prompt in analysis_prompts: try: summary = summarizer(prompt, max_length=150, min_length=30, do_sample=False) summary_text = summary[0]['summary_text'] if summary else "" # Extract prices from summary extracted_avg, extracted_min, extracted_max = extract_price_from_text(summary_text, city) if extracted_avg: avg_price = extracted_avg min_price = extracted_min max_price = extracted_max price_sources.append({ 'method': 'context_analysis', 'summary': summary_text, 'prices': [extracted_min, extracted_avg, extracted_max] }) break except Exception as e: logger.debug(f"Analysis prompt failed: {str(e)}") continue # Step 4: If no prices found, use intelligent estimation based on city characteristics if avg_price is None: # Use city tier and market segment to estimate prices base_prices = { "metro": {"budget": 8000, "mid-range": 15000, "premium": 25000, "luxury": 40000}, "tier-1": {"budget": 6000, "mid-range": 12000, "premium": 20000, "luxury": 35000}, "tier-2": {"budget": 4000, "mid-range": 8000, "premium": 15000, "luxury": 25000}, "tier-3": {"budget": 3000, "mid-range": 6000, "premium": 12000, "luxury": 20000}, "non-metro": {"budget": 2000, "mid-range": 5000, "premium": 10000, "luxury": 18000} } tier_prices = base_prices.get(city_tier, base_prices["tier-2"]) base_price = tier_prices.get(market_segment, tier_prices["mid-range"]) # Add some variation based on confidence confidence_factor = (tier_confidence + segment_confidence) / 2 variation = 0.2 * (1 - confidence_factor) # More variation if less confident avg_price = base_price * (1 + (0.5 - confidence_factor) * variation) min_price = avg_price * 0.7 max_price = avg_price * 1.5 price_sources.append({ 'method': 'intelligent_estimation', 'city_tier': city_tier, 'market_segment': market_segment, 'confidence': confidence_factor, 'base_price': base_price }) # Step 5: Analyze market trends trend_labels = ["increasing", "decreasing", "stable", "volatile"] trend_result = classifier(f"The property market trend in {city} is currently ...", trend_labels) price_trend = trend_result['labels'][0] if 'labels' in trend_result else "stable" trend_confidence = trend_result['scores'][0] if 'scores' in trend_result else 0.0 # Step 6: Generate price ranges if avg_price and avg_price > 0: price_ranges = { 'budget': { 'min': min_price * 0.6, 'max': avg_price * 0.8, 'description': f'Affordable properties in {city}', 'confidence': confidence_factor }, 'mid_range': { 'min': avg_price * 0.8, 'max': avg_price * 1.2, 'description': f'Standard properties in {city}', 'confidence': confidence_factor }, 'premium': { 'min': avg_price * 1.2, 'max': max_price * 1.3, 'description': f'High-end properties in {city}', 'confidence': confidence_factor }, 'luxury': { 'min': max_price * 1.3, 'max': max_price * 2.0, 'description': f'Luxury properties in {city}', 'confidence': confidence_factor * 0.8 } } else: price_ranges = {market_segment: {'confidence': confidence_factor}} # Step 7: Compose comprehensive result result = { 'avg_price': round(avg_price, 2) if avg_price else 0, 'min_price': round(min_price, 2) if min_price else 0, 'max_price': round(max_price, 2) if max_price else 0, 'price_ranges': price_ranges, 'price_trend': price_trend, 'city_tier': city_tier, 'tier_confidence': tier_confidence, 'market_segment': market_segment, 'segment_confidence': segment_confidence, 'price_sources': price_sources, 'last_updated': datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'data_points': len(price_sources), 'confidence': min(1.0, (tier_confidence + segment_confidence + trend_confidence) / 3), 'market_analysis': { 'trend': price_trend, 'trend_confidence': trend_confidence, 'city_tier': city_tier, 'market_segment': market_segment, 'price_per_sqft': { 'market_avg': round(avg_price, 2) if avg_price else 0, 'min': round(min_price, 2) if min_price else 0, 'max': round(max_price, 2) if max_price else 0 }, 'analysis_method': price_sources[0]['method'] if price_sources else 'estimation' } } return result except Exception as e: logger.error(f"Error in dynamic price analysis for {city}: {str(e)}") return { 'avg_price': 0, 'min_price': 0, 'max_price': 0, 'price_ranges': {}, 'price_trend': 'unknown', 'city_tier': 'unknown', 'tier_confidence': 0.0, 'market_segment': 'unknown', 'segment_confidence': 0.0, 'price_sources': [], 'last_updated': datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'data_points': 0, 'confidence': 0.0, 'market_analysis': {} } def analyze_price(data, context_text=None, latitude=None, longitude=None, property_data=None): """Enhanced price analysis using comprehensive market data and location factors""" try: # Extract basic property information price_str = str(data.get('market_value', '1')).replace('$', '').replace('₹', '').replace(',', '').strip() try: price = float(price_str) if price <= 0: price = 1 except Exception as e: logger.warning(f"Invalid price value: {price_str} ({str(e)})") price = 1 sq_ft_str = str(data.get('sq_ft', '1')).replace(',', '').strip() try: sq_ft = float(re.sub(r'[^\d.]', '', sq_ft_str)) if sq_ft <= 0: sq_ft = 1 except Exception as e: logger.warning(f"Invalid sq_ft value: {sq_ft_str} ({str(e)})") sq_ft = 1 city = data.get('city', '').strip() or 'Unknown' # Detect if this is a rental property is_rental = data.get('is_rental', False) if not is_rental: # Check status and description for rental keywords status = data.get('status', '').lower() description = data.get('description', '').lower() is_rental = any(keyword in status for keyword in ['rent', 'lease', 'let', 'hiring']) or \ any(keyword in description for keyword in ['rent', 'lease', 'let', 'hiring', 'monthly', 'per month']) # Calculate price per sq.ft properly price_per_sqft = price / sq_ft if sq_ft > 0 else price # Get market data for comparison market_data = get_hyderabad_market_data() # Adjust market data based on rental vs purchase if is_rental: # For rental properties, use monthly rental rates market_avg = 25 # ₹25/sq ft/month average for Hyderabad rentals market_min = 15 # ₹15/sq ft/month minimum market_max = 80 # ₹80/sq ft/month maximum else: # For purchase properties, use purchase rates market_avg = market_data.get('avg_price_per_sqft', 8500) if market_data else 8500 market_min = market_data.get('min_price_per_sqft', 4500) if market_data else 4500 market_max = market_data.get('max_price_per_sqft', 25000) if market_data else 25000 # Calculate deviation from market average if market_avg > 0: deviation = ((price_per_sqft - market_avg) / market_avg) * 100 else: deviation = 0 # Determine assessment based on deviation and price reasonableness - Much more lenient if is_rental: # Rental property pricing logic if price_per_sqft < 5: # Extremely low rental price assessment = "suspicious_pricing" confidence = 0.3 # Increased from 0.2 elif price_per_sqft < market_avg * 0.3: # Very below market rental assessment = "below_market" confidence = 0.5 # Increased from 0.4 elif price_per_sqft < market_avg * 0.7: # Below market rental assessment = "below_market" confidence = 0.8 # Increased from 0.7 elif price_per_sqft <= market_avg * 1.5: # Market rate rental assessment = "market_rate" confidence = 0.9 # Increased from 0.8 elif price_per_sqft <= market_avg * 2.0: # Above market rental assessment = "above_market" confidence = 0.8 # Increased from 0.7 else: # Very above market rental assessment = "premium_pricing" confidence = 0.6 # Increased from 0.5 else: # Purchase property pricing logic (existing logic) if price_per_sqft < 50: # Extremely low price - increased from 100 assessment = "suspicious_pricing" confidence = 0.2 # Increased from 0.1 elif price_per_sqft < market_avg * 0.2: # Very below market - reduced from 0.3 assessment = "below_market" confidence = 0.4 # Increased from 0.3 elif price_per_sqft < market_avg * 0.6: # Below market - reduced from 0.7 assessment = "below_market" confidence = 0.7 # Increased from 0.6 elif price_per_sqft <= market_avg * 1.5: # Market rate - increased from 1.3 assessment = "market_rate" confidence = 0.9 # Increased from 0.8 elif price_per_sqft <= market_avg * 2.5: # Above market - increased from 2.0 assessment = "above_market" confidence = 0.8 # Increased from 0.7 else: # Very above market assessment = "premium_pricing" confidence = 0.6 # Increased from 0.5 # Generate risk indicators - Much more lenient risk_indicators = [] if is_rental: if price_per_sqft < 5: # Increased from 100 risk_indicators.append("⚠️ Property priced extremely low (suspicious)") elif price_per_sqft < market_avg * 0.3: # Reduced from 0.3 risk_indicators.append("⚠️ Property priced significantly below market average") elif price_per_sqft > market_avg * 2.0: # Increased from 2.0 risk_indicators.append("⚠️ Property priced significantly above market average") else: if price_per_sqft < 50: # Increased from 100 risk_indicators.append("⚠️ Property priced extremely low (suspicious)") elif price_per_sqft < market_avg * 0.2: # Reduced from 0.3 risk_indicators.append("⚠️ Property priced significantly below market average") elif price_per_sqft > market_avg * 2.5: # Increased from 2.0 risk_indicators.append("⚠️ Property priced significantly above market average") # Price ranges for the city - Much more lenient if is_rental: price_ranges = { 'budget': { 'min': market_avg * 0.4, # Reduced from 0.5 'max': market_avg * 0.8, 'description': f'Budget rental properties in {city}' }, 'mid_range': { 'min': market_avg * 0.8, 'max': market_avg * 1.4, # Increased from 1.2 'description': f'Mid-range rental properties in {city}' }, 'premium': { 'min': market_avg * 1.4, # Reduced from 1.2 'max': market_avg * 2.5, # Increased from 2.0 'description': f'Premium rental properties in {city}' } } else: price_ranges = { 'budget': { 'min': market_avg * 0.3, # Reduced from 0.5 'max': market_avg * 0.8, 'description': f'Budget properties in {city}' }, 'mid_range': { 'min': market_avg * 0.8, 'max': market_avg * 1.4, # Increased from 1.2 'description': f'Mid-range properties in {city}' }, 'premium': { 'min': market_avg * 1.4, # Reduced from 1.2 'max': market_avg * 2.5, # Increased from 2.0 'description': f'Premium properties in {city}' } } # Determine price range price_range = "unknown" for range_name, range_data in price_ranges.items(): if range_data['min'] <= price_per_sqft <= range_data['max']: price_range = range_name break return { 'assessment': assessment, 'confidence': min(1.0, confidence), # Ensure confidence is capped at 100% 'price': price, 'formatted_price': f"₹{price:,.0f}", 'price_per_sqft': price_per_sqft, 'formatted_price_per_sqft': f"₹{price_per_sqft:,.2f}", 'price_range': price_range, 'location_price_assessment': f"Price analysis: {assessment}", 'has_price': True, 'has_sqft': True, 'is_rental': is_rental, 'market_trends': { 'trend': market_data.get('market_trend', 'unknown') if market_data else 'unknown', 'growth_rate': market_data.get('growth_rate', 0) if market_data else 0, 'inflation_rate': market_data.get('inflation_rate', 0) if market_data else 0, 'market_sentiment': market_data.get('market_sentiment', 'stable') if market_data else 'stable', 'volatility': market_data.get('market_volatility', 0) if market_data else 0 }, 'price_factors': { 'market_average': market_avg, 'deviation_percentage': deviation, 'price_reasonableness': 'suspicious' if price_per_sqft < (5 if is_rental else 50) else 'reasonable' }, 'risk_indicators': risk_indicators, 'market_average': market_avg, 'deviation_percentage': deviation, 'analysis_method': 'enhanced', 'price_ranges': price_ranges, 'city_tier': 'metro' if city.lower() in ['hyderabad', 'mumbai', 'delhi', 'bangalore', 'chennai', 'kolkata'] else 'tier2' } except Exception as e: logger.error(f"Error in comprehensive price analysis: {str(e)}") return { 'assessment': 'unknown', 'confidence': 0.0, 'price': 0, 'formatted_price': '₹0', 'price_per_sqft': 0, 'formatted_price_per_sqft': '₹0', 'price_range': 'unknown', 'location_price_assessment': 'unknown', 'has_price': False, 'has_sqft': False, 'is_rental': False, 'market_trends': {}, 'price_factors': {}, 'risk_indicators': [], 'analysis_method': 'error' }