propertyverification / models /property_summary.py
sksameermujahid's picture
Upload 23 files
6e3dbdb verified
# models/property_summary.py
from .model_loader import load_model
from .logging_config import logger
import json
import re
def validate_and_format_data(data):
"""Validate and format property data"""
if not isinstance(data, dict):
logger.warning(f"Input to validate_and_format_data is not a dict: {type(data)}")
data = {}
# Format square feet
try:
sq_ft = float(data.get('sq_ft', 0) or 0)
if sq_ft < 100: # If square feet seems too small, it might be in wrong unit
sq_ft *= 100 # Convert to square feet if it was in square meters
data['sq_ft'] = int(sq_ft)
except Exception as e:
logger.warning(f"Invalid sq_ft value: {data.get('sq_ft')}, error: {e}")
data['sq_ft'] = 0
# Format market value
try:
market_value = float(data.get('market_value', 0) or 0)
if market_value > 1000000000: # If value seems too high
market_value = market_value / 100 # Adjust if there's a decimal point issue
data['market_value'] = int(market_value)
except Exception as e:
logger.warning(f"Invalid market_value: {data.get('market_value')}, error: {e}")
data['market_value'] = 0
# Format amenities
if data.get('amenities'):
if isinstance(data['amenities'], str):
amenities = [a.strip() for a in data['amenities'].split(',') if a.strip()]
data['amenities'] = amenities
elif isinstance(data['amenities'], list):
data['amenities'] = [a.strip() for a in data['amenities'] if isinstance(a, str) and a.strip()]
else:
data['amenities'] = []
else:
data['amenities'] = []
# Ensure all expected keys exist
for key in ['bedrooms', 'bathrooms', 'year_built', 'parking_spaces', 'property_type', 'status', 'city', 'state', 'property_description', 'possession_date', 'nearby_landmarks']:
if key not in data:
data[key] = ''
return data
def format_price(price):
"""Format price in Indian currency format"""
try:
price = float(price)
if price >= 10000000: # 1 Crore
return f"₹{price/10000000:.2f} Cr"
elif price >= 100000: # 1 Lakh
return f"₹{price/100000:.2f} L"
else:
return f"₹{price:,.2f}"
except Exception as e:
logger.warning(f"Invalid price for formatting: {price}, error: {e}")
return f"₹0"
def create_property_prompt(data):
"""Create a comprehensive prompt for the SLM to generate property summary"""
# Build location string
location_parts = []
if data.get('address'):
location_parts.append(data['address'])
if data.get('city'):
location_parts.append(data['city'])
if data.get('state'):
location_parts.append(data['state'])
location = ', '.join(location_parts) if location_parts else 'Prime location'
# Build amenities string
amenities = data.get('amenities', [])
amenities_str = ', '.join(amenities[:5]) if amenities else 'Modern amenities'
# Build landmarks string
landmarks = data.get('nearby_landmarks', '')
if isinstance(landmarks, str) and landmarks:
landmarks_list = [l.strip() for l in landmarks.split(',') if l.strip()]
landmarks_str = ', '.join(landmarks_list[:3])
else:
landmarks_str = 'Convenient location'
# Create the prompt
prompt = f"""Generate a compelling 512-word property summary for an Indian real estate listing. Write in a warm, professional tone that appeals to potential buyers.
Property Information:
- Type: {data.get('property_type', 'Property')}
- Status: {data.get('status', 'Available')}
- Location: {location}
- Size: {data.get('sq_ft', '0')} sq. ft.
- Price: {format_price(data.get('market_value', '0'))}
- Bedrooms: {data.get('bedrooms', '0')}
- Bathrooms: {data.get('bathrooms', '0')}
- Year Built: {data.get('year_built', 'N/A')}
- Parking: {data.get('parking_spaces', '0')} spaces
- Possession: {data.get('possession_date', 'Immediate')}
- Amenities: {amenities_str}
- Nearby: {landmarks_str}
Description: {data.get('property_description', 'Beautiful property with modern features')}
Instructions:
1. Start with an engaging introduction about the property
2. Highlight key features and benefits
3. Emphasize location advantages
4. Mention pricing and value proposition
5. Include amenities and nearby facilities
6. End with a compelling call-to-action
7. Keep the tone warm, professional, and trustworthy
8. Use Indian real estate terminology appropriately
9. Make it exactly 512 words
Property Summary:"""
return prompt
def generate_dynamic_summary_with_slm(data):
"""Generate property summary using AI summarization model"""
try:
# Validate and format data
data = validate_and_format_data(data)
# Create the property description text
property_text = create_property_description_text(data)
# Try to use summarization model
try:
summarizer = load_model("summarization")
# Check if we have a proper summarization model
if hasattr(summarizer, 'fallback_used') and not summarizer.fallback_used:
# Use the actual AI model for summarization
result = summarizer(property_text, max_length=150, min_length=50, do_sample=False)
if isinstance(result, list) and len(result) > 0:
summary = result[0].get('summary_text', '')
if summary and len(summary.strip()) > 20:
return summary.strip()
# If AI model fails or returns poor results, use enhanced fallback
return generate_enhanced_fallback_summary(data)
except Exception as model_error:
logger.warning(f"Summarization model failed: {str(model_error)}")
return generate_enhanced_fallback_summary(data)
except Exception as e:
logger.error(f"Error in dynamic summary generation: {str(e)}")
return generate_enhanced_fallback_summary(data)
def create_property_description_text(data):
"""Create a comprehensive property description text for summarization"""
try:
# Build location string
location_parts = []
if data.get('address'):
location_parts.append(data['address'])
if data.get('city'):
location_parts.append(data['city'])
if data.get('state'):
location_parts.append(data['state'])
location = ', '.join(location_parts) if location_parts else 'Prime location'
# Build amenities string
amenities = data.get('amenities', [])
amenities_str = ', '.join(amenities[:5]) if amenities else 'Modern amenities'
# Build landmarks string
landmarks = data.get('nearby_landmarks', '')
if isinstance(landmarks, str) and landmarks:
landmarks_list = [l.strip() for l in landmarks.split(',') if l.strip()]
landmarks_str = ', '.join(landmarks_list[:3])
else:
landmarks_str = 'Convenient location'
# Create comprehensive property description
description_parts = [
f"This is a {data.get('property_type', 'property')} located in {location}.",
f"The property is currently {data.get('status', 'available')} for sale.",
f"It features {data.get('bedrooms', '0')} bedrooms and {data.get('bathrooms', '0')} bathrooms.",
f"The total area is {data.get('sq_ft', '0')} square feet.",
f"The property is priced at {format_price(data.get('market_value', '0'))}.",
f"It includes amenities such as {amenities_str}.",
f"The property is near {landmarks_str}.",
f"It was built in {data.get('year_built', 'recent years')}.",
f"The property offers {data.get('parking_spaces', '0')} parking spaces.",
f"This is an excellent investment opportunity in a prime location with modern facilities and strategic connectivity."
]
return " ".join(description_parts)
except Exception as e:
logger.error(f"Error creating property description text: {str(e)}")
return f"This is a {data.get('property_type', 'property')} located in {data.get('city', 'prime location')} with excellent features and amenities."
def generate_enhanced_fallback_summary(data):
"""Enhanced fallback summary generation with better AI-like text"""
try:
data = validate_and_format_data(data)
# Create a comprehensive and dynamic summary
summary_parts = []
# Introduction with property type and status
property_type = data.get('property_type', 'Property')
status = data.get('status', 'Available')
summary_parts.append(f"Discover this exceptional {property_type.lower()} that's currently {status.lower()} for sale.")
# Location information
location_parts = []
if data.get('city'):
location_parts.append(data['city'])
if data.get('state'):
location_parts.append(data['state'])
if location_parts:
summary_parts.append(f"This prime property is strategically located in {', '.join(location_parts)}, offering excellent connectivity and accessibility.")
# Key features section
features = []
if data.get('sq_ft'):
features.append(f"{data['sq_ft']} sq. ft. of thoughtfully designed space")
if data.get('bedrooms'):
features.append(f"{data['bedrooms']} spacious bedroom{'s' if str(data['bedrooms']) != '1' else ''}")
if data.get('bathrooms'):
features.append(f"{data['bathrooms']} modern bathroom{'s' if str(data['bathrooms']) != '1' else ''}")
if data.get('parking_spaces'):
features.append(f"{data['parking_spaces']} covered parking space{'s' if str(data['parking_spaces']) != '1' else ''}")
if features:
summary_parts.append(f"The property features {', '.join(features)}.")
# Pricing information
if data.get('market_value'):
price_str = format_price(data['market_value'])
summary_parts.append(f"Priced at {price_str}, this property offers excellent value for money and represents a sound investment opportunity.")
# Amenities and facilities
amenities = data.get('amenities', [])
if amenities:
amenities_str = ', '.join(amenities[:3])
summary_parts.append(f"The property includes modern amenities such as {amenities_str}.")
# Location benefits
landmarks = data.get('nearby_landmarks', '')
if landmarks:
summary_parts.append(f"Conveniently located near {landmarks}, this property offers easy access to essential facilities and transportation.")
# Closing statement
summary_parts.append("Perfect for families and investors alike, this property combines modern amenities with strategic location. Don't miss this opportunity to own a piece of prime real estate. Contact us today for a detailed viewing and exclusive offers.")
return " ".join(summary_parts)
except Exception as e:
logger.error(f"Error in enhanced fallback summary: {str(e)}")
return create_basic_summary(data)
def generate_property_summary(data):
"""Main function to generate property summary using AI model"""
try:
# Validate input data
if not data or not isinstance(data, dict):
return "A beautiful property with excellent features and prime location. Contact us for detailed information and exclusive offers."
# Try to use AI model for summary generation
try:
# Use the new dynamic SLM-based approach
summary = generate_dynamic_summary_with_slm(data)
# Ensure summary is a proper string
if not summary or not isinstance(summary, str):
summary = generate_enhanced_fallback_summary(data)
if not summary or not summary.strip():
summary = generate_enhanced_fallback_summary(data)
# Final fallback - always return something meaningful
if not summary or not summary.strip():
summary = create_basic_summary(data)
# Ensure it's a string and clean it up
summary = str(summary).strip()
if summary == '[object Object]' or summary == 'null' or summary == 'undefined':
summary = generate_enhanced_fallback_summary(data)
# If still no valid summary, create a basic one
if not summary or len(summary) < 50:
summary = create_basic_summary(data)
return summary
except Exception as e:
logger.error(f"Error in AI summary generation: {str(e)}")
return create_basic_summary(data)
except Exception as e:
logger.error(f"Error generating property summary: {str(e)}")
return create_basic_summary(data)
def create_basic_summary(data):
"""Create a basic summary even for invalid data"""
try:
# Extract basic information
property_type = data.get('property_type', 'Property')
city = data.get('city', 'Prime Location')
state = data.get('state', '')
bedrooms = data.get('bedrooms', '')
bathrooms = data.get('bathrooms', '')
sq_ft = data.get('sq_ft', '')
market_value = data.get('market_value', '')
# Create location string
location_parts = []
if city:
location_parts.append(city)
if state:
location_parts.append(state)
location = ', '.join(location_parts) if location_parts else 'Prime Location'
# Create features string
features = []
if bedrooms:
features.append(f"{bedrooms} bedroom{'s' if str(bedrooms) != '1' else ''}")
if bathrooms:
features.append(f"{bathrooms} bathroom{'s' if str(bathrooms) != '1' else ''}")
if sq_ft:
features.append(f"{sq_ft} sq. ft.")
features_str = ', '.join(features) if features else 'excellent features'
# Create price string
price_str = ""
if market_value:
try:
price_val = float(str(market_value).replace(',', '').replace('₹', ''))
if price_val > 0:
price_str = f" at ₹{price_val:,.0f}"
except:
pass
# Create property name - use a generic name if the original is invalid
property_name = data.get('property_name', '')
if property_name in ['2', '0', '1', 'test', 'sample', 'dummy'] or len(str(property_name)) < 3:
property_name = f"Beautiful {property_type}"
# Build the summary
summary_parts = [
f"Discover this exceptional {property_type.lower()} located in {location}.",
f"This property features {features_str} and offers excellent value for money.",
f"Perfect for families and investors alike, this property combines modern amenities with strategic location.",
f"Don't miss this opportunity to own a piece of prime real estate{price_str}.",
"Contact us today for a detailed viewing and exclusive offers."
]
return " ".join(summary_parts)
except Exception as e:
logger.error(f"Error creating basic summary: {str(e)}")
return "A beautiful property with excellent features and prime location. Contact us for detailed information and exclusive offers."