help@rskworld.in +91 93305 39277
RSK World
  • Home
  • Development
    • Web Development
    • Mobile Apps
    • Software
    • Games
    • Project
  • Technologies
    • Data Science
    • AI Development
    • Cloud Development
    • Blockchain
    • Cyber Security
    • Dev Tools
    • Testing Tools
  • Blog
  • About
  • Contact

Theme Settings

Color Scheme
Display Options
Font Size
100%
Back to Project
RSK World
real-estate-bot
/
src
RSK World
real-estate-bot
Real Estate Bot - Python + Flask + OpenAI + SQLite + Property Search + AI Chatbot + Viewing Scheduler
src
  • __pycache__
  • __init__.py476 B
  • ai_recommendation_engine.py20.6 KB
  • app.py7.8 KB
  • blockchain_integration.py1.5 KB
  • chatbot.py15.5 KB
  • database.py18.4 KB
  • image_enhancer.py7.9 KB
  • multilang_support.py8.8 KB
  • neighborhood_analyzer.py6.1 KB
  • price_prediction_engine.py25.1 KB
  • property_search.py15.6 KB
  • virtual_tour_manager.py21.8 KB
  • voice_assistant.py27.6 KB
multilang_support.pyrequirements.txt__init__.pyvirtual_tour_manager.pychatbot.py
src/multilang_support.py
Raw Download
Find: Go to:
"""
Multi-Language Support with Real-Time Translation
Author: RSK World (https://rskworld.in)
Founded by: Molla Samser
Designer & Tester: Rima Khatun
Contact: info@rskworld.com, +91 93305 39277
Year: 2026
"""

import os
import json
from typing import Dict, Any, List
from datetime import datetime

class MultiLanguageSupport:
    def __init__(self):
        """Initialize Multi-Language Support"""
        self.supported_languages = {
            'en': 'English',
            'hi': 'हिन्दी (Hindi)',
            'bn': 'বাংলা (Bengali)',
            'ta': 'தமிழ் (Tamil)',
            'te': 'తెలుగు (Telugu)',
            'mr': 'मराठी (Marathi)',
            'gu': 'ગુજરાતી (Gujarati)',
            'kn': 'ಕನ್ನಡ (Kannada)',
            'ml': 'മലയാളം (Malayalam)',
            'pa': 'ਪੰਜਾਬੀ (Punjabi)',
            'ur': 'اردو (Urdu)',
            'es': 'Español (Spanish)',
            'fr': 'Français (French)',
            'de': 'Deutsch (German)',
            'it': 'Italiano (Italian)',
            'pt': 'Português (Portuguese)',
            'ru': 'Русский (Russian)',
            'ja': '日本語 (Japanese)',
            'ko': '한국어 (Korean)',
            'zh': '中文 (Chinese)',
            'ar': 'العربية (Arabic)'
        }
        
        self.translations = self._load_translations()
        self.default_language = 'en'
    
    def _load_translations(self) -> Dict[str, Dict[str, str]]:
        """Load translation data"""
        translations = {
            'en': {
                'welcome': 'Welcome to Real Estate Bot',
                'search_properties': 'Search Properties',
                'schedule_viewing': 'Schedule Viewing',
                'property_details': 'Property Details',
                'price_prediction': 'Price Prediction',
                'virtual_tour': 'Virtual Tour',
                'contact_us': 'Contact Us',
                'bedrooms': 'Bedrooms',
                'bathrooms': 'Bathrooms',
                'area': 'Area',
                'price': 'Price',
                'location': 'Location',
                'amenities': 'Amenities',
                'year_built': 'Year Built'
            },
            'hi': {
                'welcome': 'रियल एस्टेट बॉट में आपका स्वागत है',
                'search_properties': 'प्रॉपर्टी खोजें',
                'schedule_viewing': 'व्यूइंग शेड्यूल करें',
                'property_details': 'प्रॉपर्टी विवरण',
                'price_prediction': 'मूल्य भविष्यवाणी',
                'virtual_tour': 'वर्चुअल टूर',
                'contact_us': 'संपर्क करें',
                'bedrooms': 'बेडरूम',
                'bathrooms': 'बाथरूम',
                'area': 'क्षेत्रफल',
                'price': 'कीमत',
                'location': 'स्थान',
                'amenities': 'सुविधाएं',
                'year_built': 'निर्माण वर्ष'
            },
            'bn': {
                'welcome': 'রিযেল এস্টেট বটে আপনাকে স্বাগতম',
                'search_properties': 'সম্পত্তি খুঁজুন',
                'schedule_viewing': 'ভিউয়িং শিডিউল করুন',
                'property_details': 'সম্পত্তির বিবরণ',
                'price_prediction': 'মূল্য পূর্বাভাস',
                'virtual_tour': 'ভার্চুয়াল ট্যুর',
                'contact_us': 'যোগাযোগ করুন',
                'bedrooms': 'বেডরুম',
                'bathrooms': 'বাথরুম',
                'area': 'এলাকা',
                'price': 'দাম',
                'location': 'অবস্থান',
                'amenities': '�ুবিধা',
                'year_built': 'নির্মাণ বছর'
            }
        }
        
        return translations
    
    def translate_text(self, text: str, target_language: str) -> str:
        """Translate text to target language"""
        if target_language not in self.supported_languages:
            return text
        
        if target_language == self.default_language:
            return text
        
        # Check if we have a direct translation
        translations = self.translations.get(target_language, {})
        if text in translations:
            return translations[text]
        
        # For demo purposes, return placeholder
        # In production, integrate with Google Translate API
        return f"[{self.supported_languages[target_language]}] {text}"
    
    def get_supported_languages(self) -> Dict[str, str]:
        """Get list of supported languages"""
        return self.supported_languages
    
    def detect_language(self, text: str) -> str:
        """Detect language of text (simplified)"""
        # Simple language detection based on characters
        if any(char in text for char in 'ऀँंःअआइईउऊऋएऐओऔकखगघङचछजझञटठडढणतथदधनपफबभमयरलवशषसह'):
            return 'hi'  # Hindi
        elif any(char in text for char in 'অআইঈউঊঋএঐওঔকখগঘঙচছজঝঞটঠডঢণতথদধনপফবভমযরলবশষসহ'):
            return 'bn'  # Bengali
        elif any(char in text for char in 'அஆஇஈஉஊஎஏஐஒஓஔகஙசஞடணதநபமயரலவழளறன'):
            return 'ta'  # Tamil
        else:
            return 'en'  # Default to English
    
    def format_property_data(self, property_data: Dict[str, Any], language: str) -> Dict[str, Any]:
        """Format property data in specified language"""
        formatted_data = property_data.copy()
        
        # Translate key fields
        translatable_fields = ['title', 'description', 'location']
        for field in translatable_fields:
            if field in formatted_data:
                formatted_data[f'{field}_translated'] = self.translate_text(
                    formatted_data[field], language
                )
        
        # Translate amenities
        if 'amenities' in formatted_data:
            translated_amenities = [
                self.translate_text(amenity, language) 
                for amenity in formatted_data['amenities']
            ]
            formatted_data['amenities_translated'] = translated_amenities
        
        return formatted_data
    
    def get_currency_symbol(self, language: str) -> str:
        """Get currency symbol for language"""
        currency_map = {
            'en': '₹',
            'hi': '₹',
            'bn': '₹',
            'ta': '₹',
            'te': '₹',
            'mr': '₹',
            'gu': '₹',
            'kn': '₹',
            'ml': '₹',
            'pa': '₹',
            'ur': '₹',
            'es': '€',
            'fr': '€',
            'de': '€',
            'it': '€',
            'pt': '€',
            'ru': '₽',
            'ja': '¥',
            'ko': '₩',
            'zh': '¥',
            'ar': 'ر.س'
        }
        
        return currency_map.get(language, '₹')
    
    def format_price(self, price: float, language: str) -> str:
        """Format price according to language conventions"""
        symbol = self.get_currency_symbol(language)
        
        if language in ['en', 'hi', 'bn', 'ta', 'te', 'mr', 'gu', 'kn', 'ml', 'pa', 'ur']:
            # Indian format
            formatted_price = f"{price:,.0f}".replace(',', ',')
            return f"{symbol} {formatted_price}"
        else:
            # International format
            formatted_price = f"{price:,.0f}"
            return f"{symbol}{formatted_price}"
    
    def translate_chat_response(self, response: str, user_language: str) -> str:
        """Translate chat response to user's language"""
        if user_language == self.default_language:
            return response
        
        # Split response into sentences and translate
        sentences = response.split('. ')
        translated_sentences = []
        
        for sentence in sentences:
            if sentence.strip():
                translated = self.translate_text(sentence.strip(), user_language)
                translated_sentences.append(translated)
        
        return '. '.join(translated_sentences)
211 lines•8.8 KB
python
requirements.txt
Raw Download
Find: Go to:
flask==2.3.3
openai==1.3.5
requests==2.31.0
python-dotenv==1.0.0
flask-cors==4.0.0
jinja2==3.1.2
gunicorn==21.2.0
numpy==1.24.3
pandas==2.0.3
scikit-learn==1.3.0
opencv-python==4.8.1.78
Pillow==10.0.1
speechrecognition==3.10.0
pyttsx3==2.90
joblib==1.3.2
web3==6.11.0
17 lines•284 B
text
src/__init__.py
Raw Download
Find: Go to:
"""
Real Estate Bot - Python Package Initialization
Author: RSK World (https://rskworld.in)
Founded by: Molla Samser
Designer & Tester: Rima Khatun
Contact: info@rskworld.com, +91 93305 39277
Year: 2026
Description: Real estate chatbot for property search, inquiries, and scheduling viewings
"""

__version__ = "1.0.0"
__author__ = "RSK World"
__email__ = "info@rskworld.com"
__description__ = "AI-powered real estate chatbot for property search and management"
15 lines•476 B
python
src/virtual_tour_manager.py
Raw Download
Find: Go to:
"""
Virtual Property Tour Manager with 360° View Support
Author: RSK World (https://rskworld.in)
Founded by: Molla Samser
Designer & Tester: Rima Khatun
Contact: info@rskworld.com, +91 93305 39277
Year: 2026
Description: Advanced virtual tour system with 360° panoramic views and interactive features
"""

import os
import json
import base64
from typing import List, Dict, Any, Optional
from datetime import datetime
import cv2
import numpy as np
from PIL import Image, ImageEnhance
import io

class VirtualTourManager:
    def __init__(self, database_manager):
        """
        Initialize Virtual Tour Manager
        
        Args:
            database_manager: Database manager instance
        """
        self.db_manager = database_manager
        self.tour_data_dir = 'data/virtual_tours'
        self.panorama_dir = 'data/panoramas'
        os.makedirs(self.tour_data_dir, exist_ok=True)
        os.makedirs(self.panorama_dir, exist_ok=True)
        
        # Supported formats for virtual tours
        self.supported_formats = {
            '360_image': ['.jpg', '.jpeg', '.png'],
            '360_video': ['.mp4', '.webm', '.mov'],
            '3d_model': ['.glb', '.gltf', '.obj'],
            'floor_plan': ['.svg', '.png', '.jpg']
        }
    
    def create_virtual_tour(self, property_id: int, tour_data: Dict[str, Any]) -> Dict[str, Any]:
        """
        Create a new virtual tour for a property
        
        Args:
            property_id: Property ID
            tour_data: Tour configuration data
            
        Returns:
            Created tour information
        """
        tour_id = f"tour_{property_id}_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
        
        tour_config = {
            'tour_id': tour_id,
            'property_id': property_id,
            'created_at': datetime.now().isoformat(),
            'title': tour_data.get('title', f'Virtual Tour - Property {property_id}'),
            'description': tour_data.get('description', ''),
            'scenes': [],
            'navigation': tour_data.get('navigation', {}),
            'hotspots': tour_data.get('hotspots', []),
            'settings': {
                'auto_rotate': tour_data.get('auto_rotate', True),
                'start_scene': tour_data.get('start_scene', 0),
                'transition_speed': tour_data.get('transition_speed', 1.0),
                'enable_controls': tour_data.get('enable_controls', True),
                'fullscreen_enabled': tour_data.get('fullscreen_enabled', True)
            }
        }
        
        # Process scenes
        for i, scene in enumerate(tour_data.get('scenes', [])):
            processed_scene = self._process_scene(scene, i, tour_id)
            tour_config['scenes'].append(processed_scene)
        
        # Save tour configuration
        tour_file = os.path.join(self.tour_data_dir, f'{tour_id}.json')
        with open(tour_file, 'w') as f:
            json.dump(tour_config, f, indent=2)
        
        return {
            'success': True,
            'tour_id': tour_id,
            'message': 'Virtual tour created successfully',
            'tour_config': tour_config
        }
    
    def _process_scene(self, scene: Dict[str, Any], scene_index: int, tour_id: str) -> Dict[str, Any]:
        """Process individual scene for virtual tour"""
        processed_scene = {
            'scene_id': f"scene_{scene_index}",
            'name': scene.get('name', f'Scene {scene_index + 1}'),
            'type': scene.get('type', '360_image'),
            'media_path': scene.get('media_path', ''),
            'thumbnail': scene.get('thumbnail', ''),
            'hotspots': scene.get('hotspots', []),
            'navigation': {
                'look_at': scene.get('look_at', [0, 0, 0]),
                'camera_position': scene.get('camera_position', [0, 0, 5]),
                'fov': scene.get('fov', 75)
            },
            'lighting': scene.get('lighting', {
                'ambient': 0.6,
                'directional': 0.4,
                'direction': [1, 1, -1]
            }),
            'audio': scene.get('audio', {
                'background_music': '',
                'narration': '',
                'ambient_sounds': []
            })
        }
        
        # Process media based on type
        if processed_scene['type'] == '360_image':
            processed_scene['media_path'] = self._process_360_image(
                scene.get('media_path'), tour_id, scene_index
            )
        elif processed_scene['type'] == '360_video':
            processed_scene['media_path'] = self._process_360_video(
                scene.get('media_path'), tour_id, scene_index
            )
        elif processed_scene['type'] == '3d_model':
            processed_scene['media_path'] = self._process_3d_model(
                scene.get('media_path'), tour_id, scene_index
            )
        
        return processed_scene
    
    def _process_360_image(self, image_path: str, tour_id: str, scene_index: int) -> str:
        """Process 360° panoramic image"""
        if not image_path:
            return ''
        
        try:
            # Load and enhance the image
            image = Image.open(image_path)
            
            # Enhance image quality
            enhancer = ImageEnhance.Brightness(image)
            image = enhancer.enhance(1.1)
            
            enhancer = ImageEnhance.Contrast(image)
            image = enhancer.enhance(1.1)
            
            enhancer = ImageEnhance.Sharpness(image)
            image = enhancer.enhance(1.1)
            
            # Save processed image
            processed_filename = f'{tour_id}_scene_{scene_index}_360.jpg'
            processed_path = os.path.join(self.panorama_dir, processed_filename)
            image.save(processed_path, 'JPEG', quality=95)
            
            return f'panoramas/{processed_filename}'
            
        except Exception as e:
            print(f"Error processing 360 image: {e}")
            return image_path
    
    def _process_360_video(self, video_path: str, tour_id: str, scene_index: int) -> str:
        """Process 360° video"""
        if not video_path:
            return ''
        
        # For video processing, we would typically use FFmpeg
        # For now, return the original path
        return video_path
    
    def _process_3d_model(self, model_path: str, tour_id: str, scene_index: int) -> str:
        """Process 3D model"""
        if not model_path:
            return ''
        
        # For 3D model processing, we would use tools like Blender
        # For now, return the original path
        return model_path
    
    def get_virtual_tour(self, tour_id: str) -> Optional[Dict[str, Any]]:
        """Get virtual tour configuration"""
        tour_file = os.path.join(self.tour_data_dir, f'{tour_id}.json')
        
        if not os.path.exists(tour_file):
            return None
        
        try:
            with open(tour_file, 'r') as f:
                tour_config = json.load(f)
            
            return tour_config
            
        except Exception as e:
            print(f"Error loading tour {tour_id}: {e}")
            return None
    
    def generate_tour_viewer_html(self, tour_id: str) -> str:
        """Generate HTML for virtual tour viewer"""
        tour_config = self.get_virtual_tour(tour_id)
        
        if not tour_config:
            return "<div>Tour not found</div>"
        
        html_template = f"""
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{tour_config['title']} - Virtual Tour</title>
    <script src="https://aframe.io/releases/1.3.0/aframe.min.js"></script>
    <script src="https://unpkg.com/aframe-event-set-component@5.0.0/dist/aframe-event-set-component.min.js"></script>
    <style>
        body {{
            margin: 0;
            font-family: Arial, sans-serif;
            overflow: hidden;
        }}
        
        .tour-controls {{
            position: fixed;
            top: 20px;
            left: 20px;
            z-index: 1000;
            background: rgba(0,0,0,0.7);
            color: white;
            padding: 15px;
            border-radius: 10px;
            max-width: 300px;
        }}
        
        .scene-selector {{
            margin-bottom: 15px;
        }}
        
        .scene-btn {{
            display: block;
            width: 100%;
            margin: 5px 0;
            padding: 8px;
            background: #3498db;
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
        }}
        
        .scene-btn:hover {{
            background: #2980b9;
        }}
        
        .scene-btn.active {{
            background: #e74c3c;
        }}
        
        .tour-info {{
            position: fixed;
            bottom: 20px;
            right: 20px;
            background: rgba(0,0,0,0.7);
            color: white;
            padding: 15px;
            border-radius: 10px;
            max-width: 300px;
        }}
        
        .hotspot {{
            position: absolute;
            width: 30px;
            height: 30px;
            background: #e74c3c;
            border-radius: 50%;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-weight: bold;
            z-index: 100;
        }}
        
        .hotspot-info {{
            position: absolute;
            background: white;
            color: black;
            padding: 10px;
            border-radius: 5px;
            display: none;
            z-index: 101;
            max-width: 200px;
        }}
    </style>
</head>
<body>
    <div class="tour-controls">
        <h3>Virtual Tour Controls</h3>
        <div class="scene-selector">
            <h4>Scenes:</h4>
            {self._generate_scene_buttons(tour_config['scenes'])}
        </div>
        <div class="tour-settings">
            <label>
                <input type="checkbox" id="autoRotate" checked> Auto Rotate
            </label>
            <br>
            <label>
                <input type="checkbox" id="fullscreen"> Fullscreen
            </label>
        </div>
    </div>
    
    <div class="tour-info">
        <h4>{tour_config['title']}</h4>
        <p>{tour_config['description']}</p>
        <small>Use mouse to look around, scroll to zoom</small>
    </div>
    
    <a-scene embedded style="height: 100vh; width: 100vw;">
        <a-assets>
            {self._generate_scene_assets(tour_config['scenes'])}
        </a-assets>
        
        {self._generate_scene_elements(tour_config['scenes'])}
        
        <a-sky id="sky"></a-sky>
        
        <a-camera id="camera" 
                  look-controls="enabled: true"
                  wasd-controls="enabled: false">
        </a-camera>
    </a-scene>
    
    <script>
        let currentScene = 0;
        const scenes = {json.dumps([scene['scene_id'] for scene in tour_config['scenes']])};
        const tourConfig = {json.dumps(tour_config)};
        
        function loadScene(sceneIndex) {{
            const scene = tourConfig.scenes[sceneIndex];
            const sky = document.querySelector('#sky');
            
            if (scene.type === '360_image') {{
                sky.setAttribute('src', `#${{scene.scene_id}}_image`);
            }} else if (scene.type === '360_video') {{
                sky.setAttribute('src', `#${{scene.scene_id}}_video`);
            }}
            
            // Update camera position
            const camera = document.querySelector('#camera');
            camera.setAttribute('position', scene.navigation.camera_position.join(' '));
            camera.setAttribute('look-at', scene.navigation.look_at.join(' '));
            
            // Update active button
            document.querySelectorAll('.scene-btn').forEach((btn, index) => {{
                btn.classList.toggle('active', index === sceneIndex);
            }});
            
            currentScene = sceneIndex;
        }}
        
        function setupHotspots() {{
            const scene = tourConfig.scenes[currentScene];
            
            // Remove existing hotspots
            document.querySelectorAll('.hotspot').forEach(el => el.remove());
            
            // Add hotspots for current scene
            scene.hotspots.forEach((hotspot, index) => {{
                const hotspotEl = document.createElement('div');
                hotspotEl.className = 'hotspot';
                hotspotEl.style.left = hotspot.position[0] + '%';
                hotspotEl.style.top = hotspot.position[1] + '%';
                hotspotEl.textContent = index + 1;
                
                const infoEl = document.createElement('div');
                infoEl.className = 'hotspot-info';
                infoEl.innerHTML = `
                    <strong>${{hotspot.title}}</strong><br>
                    ${{hotspot.description}}
                `;
                
                hotspotEl.appendChild(infoEl);
                
                hotspotEl.addEventListener('mouseenter', () => {{
                    infoEl.style.display = 'block';
                }});
                
                hotspotEl.addEventListener('mouseleave', () => {{
                    infoEl.style.display = 'none';
                }});
                
                if (hotspot.action) {{
                    hotspotEl.addEventListener('click', () => {{
                        if (hotspot.action.type === 'navigate_to_scene') {{
                            loadScene(hotspot.action.scene_index);
                        }}
                    }});
                }}
                
                document.body.appendChild(hotspotEl);
            }});
        }}
        
        // Initialize
        document.addEventListener('DOMContentLoaded', () => {{
            loadScene(0);
            setupHotspots();
            
            // Setup scene buttons
            document.querySelectorAll('.scene-btn').forEach((btn, index) => {{
                btn.addEventListener('click', () => loadScene(index));
            }});
            
            // Setup controls
            document.getElementById('autoRotate').addEventListener('change', (e) => {{
                const camera = document.querySelector('#camera');
                if (e.target.checked) {{
                    camera.setAttribute('animation', 'property: rotation; to: 0 360 0; dur: 60s; loop: true');
                }} else {{
                    camera.removeAttribute('animation');
                }}
            }});
            
            document.getElementById('fullscreen').addEventListener('change', (e) => {{
                if (e.target.checked) {{
                    document.documentElement.requestFullscreen();
                }} else {{
                    document.exitFullscreen();
                }}
            }});
        }});
    </script>
</body>
</html>
        """
        
        return html_template
    
    def _generate_scene_buttons(self, scenes: List[Dict[str, Any]]) -> str:
        """Generate HTML buttons for scene selection"""
        buttons = []
        for i, scene in enumerate(scenes):
            active_class = 'active' if i == 0 else ''
            buttons.append(f'<button class="scene-btn {active_class}" onclick="loadScene({i})">{scene["name"]}</button>')
        return '\n'.join(buttons)
    
    def _generate_scene_assets(self, scenes: List[Dict[str, Any]]) -> str:
        """Generate A-Frame assets for scenes"""
        assets = []
        for scene in scenes:
            if scene['type'] == '360_image':
                assets.append(f'<img id="{scene["scene_id"]}_image" src="{scene["media_path"]}" crossorigin="anonymous">')
            elif scene['type'] == '360_video':
                assets.append(f'<video id="{scene["scene_id"]}_video" src="{scene["media_path"]}" autoplay loop muted crossorigin="anonymous"></video>')
        return '\n'.join(assets)
    
    def _generate_scene_elements(self, scenes: List[Dict[str, Any]]) -> str:
        """Generate A-Frame scene elements"""
        elements = []
        for scene in scenes:
            # Add lighting
            if scene.get('lighting'):
                lighting = scene['lighting']
                direction = lighting.get('direction', [1, 1, -1])
                direction_str = ' '.join(map(str, direction))
                elements.append(f'''
                    <a-light type="ambient" color="#fff" intensity="{lighting.get('ambient', 0.6)}"></a-light>
                    <a-light type="directional" color="#fff" intensity="{lighting.get('directional', 0.4)}" 
                             position="{direction_str}"></a-light>
                ''')
        return '\n'.join(elements)
    
    def create_interactive_floor_plan(self, property_id: int, floor_plan_data: Dict[str, Any]) -> Dict[str, Any]:
        """Create interactive floor plan with hotspots"""
        floor_plan_id = f"floor_plan_{property_id}_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
        
        floor_plan_config = {
            'floor_plan_id': floor_plan_id,
            'property_id': property_id,
            'created_at': datetime.now().isoformat(),
            'title': floor_plan_data.get('title', f'Floor Plan - Property {property_id}'),
            'image_path': floor_plan_data.get('image_path', ''),
            'dimensions': floor_plan_data.get('dimensions', {}),
            'rooms': floor_plan_data.get('rooms', []),
            'hotspots': floor_plan_data.get('hotspots', []),
            'measurements': floor_plan_data.get('measurements', {}),
            'interactive_features': {
                'enable_room_hover': floor_plan_data.get('enable_room_hover', True),
                'enable_measurement_tool': floor_plan_data.get('enable_measurement_tool', True),
                'enable_3d_view': floor_plan_data.get('enable_3d_view', True),
                'enable_furniture_placement': floor_plan_data.get('enable_furniture_placement', False)
            }
        }
        
        # Save floor plan configuration
        floor_plan_file = os.path.join(self.tour_data_dir, f'{floor_plan_id}.json')
        with open(floor_plan_file, 'w') as f:
            json.dump(floor_plan_config, f, indent=2)
        
        return {
            'success': True,
            'floor_plan_id': floor_plan_id,
            'message': 'Interactive floor plan created successfully',
            'config': floor_plan_config
        }
    
    def generate_ar_overlay_data(self, property_id: int) -> Dict[str, Any]:
        """Generate AR overlay data for mobile AR viewing"""
        property_data = self.db_manager.get_property_by_id(property_id)
        
        if not property_data:
            return {'success': False, 'error': 'Property not found'}
        
        ar_data = {
            'property_id': property_id,
            'ar_markers': [],
            'overlays': [],
            'tracking_data': {
                'marker_type': 'image',
                'marker_size': 0.1,
                'tracking_confidence': 0.8
            }
        }
        
        # Generate AR markers for different rooms
        rooms = ['Living Room', 'Bedroom', 'Kitchen', 'Bathroom']
        for i, room in enumerate(rooms):
            ar_data['ar_markers'].append({
                'marker_id': f'marker_{i}',
                'room_name': room,
                'position': [i * 2, 0, 0],
                'content': {
                    'title': room,
                    'description': f'Virtual {room} view',
                    'media_url': f'ar_content/{property_id}_{room.lower().replace(" ", "_")}.glb',
                    'scale': [1, 1, 1],
                    'rotation': [0, 0, 0]
                }
            })
        
        # Add information overlays
        ar_data['overlays'] = [
            {
                'type': 'price_info',
                'content': f"₹{property_data.get('price', 0):,}",
                'position': [0, 2, 0],
                'style': 'large_text'
            },
            {
                'type': 'property_details',
                'content': f"{property_data.get('bedrooms', 0)}BHK • {property_data.get('area_sqft', 0)} sqft",
                'position': [0, 1.5, 0],
                'style': 'medium_text'
            }
        ]
        
        return {
            'success': True,
            'ar_data': ar_data,
            'message': 'AR data generated successfully'
        }
    
    def get_tour_analytics(self, tour_id: str) -> Dict[str, Any]:
        """Get analytics data for a virtual tour"""
        # This would typically track user interactions, view times, etc.
        # For now, return mock analytics
        
        analytics = {
            'tour_id': tour_id,
            'total_views': 1250,
            'unique_viewers': 890,
            'average_view_time': 245,  # seconds
            'completion_rate': 0.78,
            'most_viewed_scene': 'scene_2',
            'drop_off_points': ['scene_0', 'scene_3'],
            'device_breakdown': {
                'desktop': 0.65,
                'mobile': 0.28,
                'tablet': 0.07
            },
            'interaction_data': {
                'hotspot_clicks': 342,
                'scene_transitions': 1890,
                'fullscreen_usage': 0.45,
                'auto_rotate_usage': 0.72
            }
        }
        
        return analytics
591 lines•21.8 KB
python
src/chatbot.py
Raw Download
Find: Go to:
"""
Real Estate Chatbot Core Logic
Author: RSK World (https://rskworld.in)
Founded by: Molla Samser
Designer & Tester: Rima Khatun
Contact: info@rskworld.com, +91 93305 39277
Year: 2026
"""

import re
from datetime import datetime, timedelta
from typing import List, Dict, Any

class RealEstateChatbot:
    def __init__(self, openai_client, property_search_engine, database_manager):
        """
        Initialize the Real Estate Chatbot
        
        Args:
            openai_client: OpenAI API client
            property_search_engine: Property search engine instance
            database_manager: Database manager instance
        """
        self.openai = openai_client
        self.property_search = property_search_engine
        self.db_manager = database_manager
        self.conversation_history = {}
        
    def process_message(self, message: str, user_id: str) -> str:
        """
        Process user message and generate response
        
        Args:
            message: User's message
            user_id: User identifier
            
        Returns:
            Chatbot response
        """
        # Initialize conversation history if not exists
        if user_id not in self.conversation_history:
            self.conversation_history[user_id] = []
        
        # Add user message to history
        self.conversation_history[user_id].append({
            'role': 'user',
            'content': message,
            'timestamp': datetime.now()
        })
        
        # Determine intent and extract entities
        intent, entities = self._analyze_message(message)
        
        # Generate response based on intent
        response = self._generate_response(intent, entities, user_id)
        
        # Add bot response to history
        self.conversation_history[user_id].append({
            'role': 'assistant',
            'content': response,
            'timestamp': datetime.now()
        })
        
        # Keep only last 10 messages in history
        if len(self.conversation_history[user_id]) > 10:
            self.conversation_history[user_id] = self.conversation_history[user_id][-10:]
        
        return response
    
    def _analyze_message(self, message: str) -> tuple:
        """
        Analyze user message to determine intent and extract entities
        
        Args:
            message: User's message
            
        Returns:
            Tuple of (intent, entities)
        """
        message_lower = message.lower()
        
        # Property search patterns
        search_patterns = [
            r'(?:search|find|looking for|show me).*(?:property|house|home|apartment|flat)',
            r'(?:property|house|home|apartment|flat).*(?:in|at|near)',
            r'(?:buy|rent|lease).*(?:property|house|home|apartment|flat)'
        ]
        
        # Scheduling patterns
        scheduling_patterns = [
            r'(?:schedule|book|arrange).*(?:viewing|visit|tour|appointment)',
            r'(?:see|visit|view).*(?:property|house|home)',
            r'(?:when|what time).*(?:available|can.*visit)'
        ]
        
        # Inquiry patterns
        inquiry_patterns = [
            r'(?:tell me|what|how).*(?:about|regarding)',
            r'(?:information|details).*(?:about|of)',
            r'(?:price|cost|rate).*(?:of|for)'
        ]
        
        # Check for intent
        intent = 'general'
        for pattern in search_patterns:
            if re.search(pattern, message_lower):
                intent = 'property_search'
                break
        
        if intent == 'general':
            for pattern in scheduling_patterns:
                if re.search(pattern, message_lower):
                    intent = 'schedule_viewing'
                    break
        
        if intent == 'general':
            for pattern in inquiry_patterns:
                if re.search(pattern, message_lower):
                    intent = 'property_inquiry'
                    break
        
        # Extract entities
        entities = self._extract_entities(message, intent)
        
        return intent, entities
    
    def _extract_entities(self, message: str, intent: str) -> Dict[str, Any]:
        """
        Extract entities from user message
        
        Args:
            message: User's message
            intent: Detected intent
            
        Returns:
            Dictionary of extracted entities
        """
        entities = {}
        message_lower = message.lower()
        
        # Extract location
        location_patterns = [
            r'(?:in|at|near)\s+([a-z\s]+(?:city|area|location|place|district|state))',
            r'([a-z\s]+(?:city|area|location|place|district|state))\s*(?:property|house|home)',
        ]
        
        for pattern in location_patterns:
            match = re.search(pattern, message_lower)
            if match:
                entities['location'] = match.group(1).strip()
                break
        
        # Extract price range
        price_patterns = [
            r'(?:under|below|less than)\s*(?:\$|₹|rs|rupees)?\s*(\d+(?:,\d+)*)',
            r'(?:between|range)\s*(?:\$|₹|rs|rupees)?\s*(\d+(?:,\d+)*)\s*(?:and|to|-)\s*(?:\$|₹|rs|rupees)?\s*(\d+(?:,\d+)*)',
            r'(?:over|above|more than)\s*(?:\$|₹|rs|rupees)?\s*(\d+(?:,\d+)*)'
        ]
        
        for pattern in price_patterns:
            match = re.search(pattern, message_lower)
            if match:
                if len(match.groups()) == 2:
                    entities['price_min'] = int(match.group(1).replace(',', ''))
                    entities['price_max'] = int(match.group(2).replace(',', ''))
                else:
                    if 'under' in pattern or 'below' in pattern or 'less than' in pattern:
                        entities['price_max'] = int(match.group(1).replace(',', ''))
                    else:
                        entities['price_min'] = int(match.group(1).replace(',', ''))
                break
        
        # Extract property type
        property_types = {
            'apartment': ['apartment', 'flat', 'unit'],
            'house': ['house', 'home', 'villa', 'bungalow'],
            'condo': ['condo', 'condominium'],
            'townhouse': ['townhouse', 'town home']
        }
        
        for prop_type, keywords in property_types.items():
            if any(keyword in message_lower for keyword in keywords):
                entities['property_type'] = prop_type
                break
        
        # Extract bedrooms
        bedroom_match = re.search(r'(\d+)\s*(?:bedroom|bed|bhk)', message_lower)
        if bedroom_match:
            entities['bedrooms'] = int(bedroom_match.group(1))
        
        # Extract date/time for scheduling
        if intent == 'schedule_viewing':
            date_patterns = [
                r'(?:tomorrow|today|next week|this week)',
                r'\d{1,2}[/-]\d{1,2}[/-]\d{2,4}',
                r'(?:monday|tuesday|wednesday|thursday|friday|saturday|sunday)'
            ]
            
            for pattern in date_patterns:
                match = re.search(pattern, message_lower)
                if match:
                    entities['preferred_date'] = match.group(0)
                    break
        
        # Extract property ID if mentioned
        property_id_match = re.search(r'property\s*(?:id|#|number)?\s*:?\s*(\d+)', message_lower)
        if property_id_match:
            try:
                entities['property_id'] = int(property_id_match.group(1))
            except ValueError:
                pass
        
        return entities
    
    def _generate_response(self, intent: str, entities: Dict[str, Any], user_id: str) -> str:
        """
        Generate response based on intent and entities
        
        Args:
            intent: User's intent
            entities: Extracted entities
            user_id: User identifier
            
        Returns:
            Generated response
        """
        if intent == 'property_search':
            return self._handle_property_search(entities, user_id)
        elif intent == 'schedule_viewing':
            return self._handle_schedule_viewing(entities, user_id)
        elif intent == 'property_inquiry':
            return self._handle_property_inquiry(entities, user_id)
        else:
            return self._handle_general_query(entities, user_id)
    
    def _handle_property_search(self, entities: Dict[str, Any], user_id: str) -> str:
        """Handle property search requests"""
        try:
            # Search for properties based on criteria
            properties = self.property_search.search(entities)
            
            if not properties:
                return "I couldn't find any properties matching your criteria. Would you like to try with different search parameters?"
            
            # Format response
            response = f"I found {len(properties)} properties matching your criteria:\n\n"
            
            for i, prop in enumerate(properties[:5], 1):  # Show top 5 results
                area = prop.get('area_sqft', prop.get('area', 'N/A'))
                area_str = f"{area} sqft" if isinstance(area, (int, float)) else str(area)
                price = prop.get('price', 'Price not specified')
                price_str = f"₹{price:,}" if isinstance(price, (int, float)) else str(price)
                
                response += f"{i}. {prop.get('title', 'Property Title')}\n"
                response += f"   📍 {prop.get('location', 'Location not specified')}\n"
                response += f"   💰 {price_str}\n"
                response += f"   🏠 {prop.get('bedrooms', 'N/A')} bedrooms, {prop.get('bathrooms', 'N/A')} bathrooms\n"
                response += f"   📐 {area_str}\n\n"
            
            if len(properties) > 5:
                response += f"And {len(properties) - 5} more properties. Would you like to see more details about any specific property?"
            
            return response
            
        except Exception as e:
            return f"I apologize, but I encountered an error while searching for properties: {str(e)}"
    
    def _handle_schedule_viewing(self, entities: Dict[str, Any], user_id: str) -> str:
        """Handle viewing scheduling requests"""
        try:
            property_id = entities.get('property_id')
            preferred_date = entities.get('preferred_date')
            
            if not property_id:
                # Try to find property from recent search results or ask user
                return ("To schedule a viewing, please specify which property you're interested in. "
                       "You can mention the property ID (e.g., 'Schedule viewing for property 1') "
                       "or first search for properties and then mention which one you'd like to view.")
            
            # Check if property exists
            property_info = self.property_search.get_property_by_id(property_id)
            if not property_info:
                return (f"I couldn't find property ID {property_id}. "
                       "Please check the property ID and try again, or search for available properties first.")
            
            # Schedule appointment
            appointment_id = self.db_manager.schedule_appointment(
                user_id=user_id,
                property_id=property_id,
                date_time=preferred_date or datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
                contact_info=entities
            )
            
            response = f"Great! I've scheduled your viewing for:\n\n"
            response += f"🏠 Property: {property_info.get('title', 'Property Title')}\n"
            response += f"📍 Location: {property_info.get('location', 'Location not specified')}\n"
            response += f"📅 Date: {preferred_date or 'To be confirmed'}\n"
            response += f"📋 Appointment ID: {appointment_id}\n\n"
            response += "Our team will contact you shortly to confirm the exact time. You can reach us at +91 93305 39277 for any questions."
            
            return response
            
        except Exception as e:
            return f"I apologize, but I encountered an error while scheduling your viewing: {str(e)}"
    
    def _handle_property_inquiry(self, entities: Dict[str, Any], user_id: str) -> str:
        """Handle property inquiries"""
        try:
            property_id = entities.get('property_id')
            
            if property_id:
                # Get specific property details
                property_info = self.property_search.get_property_by_id(property_id)
                if property_info:
                    response = f"Here are the details for {property_info.get('title', 'Property Title')}:\n\n"
                    area = property_info.get('area_sqft', property_info.get('area', 'Not specified'))
                    area_str = f"{area} sqft" if isinstance(area, (int, float)) else str(area)
                    price = property_info.get('price', 'Not specified')
                    price_str = f"₹{price:,}" if isinstance(price, (int, float)) else str(price)
                    
                    response += f"📍 **Location:** {property_info.get('location', 'Not specified')}\n"
                    response += f"💰 **Price:** {price_str}\n"
                    response += f"🏠 **Type:** {property_info.get('property_type', 'Not specified')}\n"
                    response += f"🛏️ **Bedrooms:** {property_info.get('bedrooms', 'Not specified')}\n"
                    response += f"🚿 **Bathrooms:** {property_info.get('bathrooms', 'Not specified')}\n"
                    response += f"📐 **Area:** {area_str}\n"
                    response += f"📝 **Description:** {property_info.get('description', 'No description available')}\n\n"
                    response += "Would you like to schedule a viewing or do you have any specific questions about this property?"
                    return response
            
            # General inquiry response
            return ("I'd be happy to help you with information about our properties. You can ask me about:\n\n"
                   "• Property prices and availability\n"
                   "• Location details and neighborhoods\n"
                   "• Property features and amenities\n"
                   "• Scheduling viewings\n"
                   "• General real estate questions\n\n"
                   "What specific information are you looking for?")
            
        except Exception as e:
            return f"I apologize, but I encountered an error while processing your inquiry: {str(e)}"
    
    def _handle_general_query(self, entities: Dict[str, Any], user_id: str) -> str:
        """Handle general queries"""
        return """Hello! I'm your Real Estate Assistant, here to help you find your perfect property. I can help you with:

🏠 **Property Search:** Find properties based on location, price, type, and features
📅 **Schedule Viewings:** Book appointments to visit properties
💬 **Property Information:** Get detailed information about specific properties
📍 **Location Insights:** Learn about neighborhoods and areas

You can ask me questions like:
• "Show me apartments in Mumbai under 50 lakhs"
• "I'm looking for a 3-bedroom house in Delhi"
• "Schedule a viewing for property ID 123"
• "What's the price of the 2BHK flat in Bangalore?"

How can I assist you today?"""
359 lines•15.5 KB
python
🚀 Support RSK World

Subscribe to our YouTube channel for latest tutorials & updates!



Click subscribe & support our work ❤️

About RSK World

Founded by Molla Samser, with Designer & Tester Rima Khatun, RSK World is your one-stop destination for free programming resources, source code, and development tools.

Founder: Molla Samser
Designer & Tester: Rima Khatun

Development

  • Game Development
  • Web Development
  • Mobile Development
  • AI Development
  • Development Tools

Legal

  • Terms & Conditions
  • Privacy Policy
  • Disclaimer

Contact Info

Nutanhat, Mongolkote
Purba Burdwan, West Bengal
India, 713147

+91 93305 39277

hello@rskworld.in
support@rskworld.in

© 2026 RSK World. All rights reserved.

Content used for educational purposes only. View Disclaimer