|
|
|
|
|
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 = {} |
|
|
|
|
|
try: |
|
sq_ft = float(data.get('sq_ft', 0) or 0) |
|
if sq_ft < 100: |
|
sq_ft *= 100 |
|
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 |
|
|
|
|
|
try: |
|
market_value = float(data.get('market_value', 0) or 0) |
|
if market_value > 1000000000: |
|
market_value = market_value / 100 |
|
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 |
|
|
|
|
|
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'] = [] |
|
|
|
|
|
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: |
|
return f"₹{price/10000000:.2f} Cr" |
|
elif price >= 100000: |
|
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""" |
|
|
|
|
|
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' |
|
|
|
|
|
amenities = data.get('amenities', []) |
|
amenities_str = ', '.join(amenities[:5]) if amenities else 'Modern amenities' |
|
|
|
|
|
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' |
|
|
|
|
|
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: |
|
|
|
data = validate_and_format_data(data) |
|
|
|
|
|
property_text = create_property_description_text(data) |
|
|
|
|
|
try: |
|
summarizer = load_model("summarization") |
|
|
|
|
|
if hasattr(summarizer, 'fallback_used') and not summarizer.fallback_used: |
|
|
|
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() |
|
|
|
|
|
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: |
|
|
|
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' |
|
|
|
|
|
amenities = data.get('amenities', []) |
|
amenities_str = ', '.join(amenities[:5]) if amenities else 'Modern amenities' |
|
|
|
|
|
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' |
|
|
|
|
|
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) |
|
|
|
|
|
summary_parts = [] |
|
|
|
|
|
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_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.") |
|
|
|
|
|
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)}.") |
|
|
|
|
|
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 = data.get('amenities', []) |
|
if amenities: |
|
amenities_str = ', '.join(amenities[:3]) |
|
summary_parts.append(f"The property includes modern amenities such as {amenities_str}.") |
|
|
|
|
|
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.") |
|
|
|
|
|
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: |
|
|
|
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: |
|
|
|
summary = generate_dynamic_summary_with_slm(data) |
|
|
|
|
|
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) |
|
|
|
|
|
if not summary or not summary.strip(): |
|
summary = create_basic_summary(data) |
|
|
|
|
|
summary = str(summary).strip() |
|
if summary == '[object Object]' or summary == 'null' or summary == 'undefined': |
|
summary = generate_enhanced_fallback_summary(data) |
|
|
|
|
|
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: |
|
|
|
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', '') |
|
|
|
|
|
location_parts = [] |
|
if city: |
|
location_parts.append(city) |
|
if state: |
|
location_parts.append(state) |
|
location = ', '.join(location_parts) if location_parts else 'Prime Location' |
|
|
|
|
|
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' |
|
|
|
|
|
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 |
|
|
|
|
|
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}" |
|
|
|
|
|
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." |
|
|