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
chat.js
static/js/chat.js
Raw Download
Find: Go to:
/**
 * Real Estate Bot - Chat JavaScript
 * Author: RSK World (https://rskworld.in)
 * Founded by: Molla Samser
 * Designer & Tester: Rima Khatun
 * Contact: info@rskworld.com, +91 93305 39277
 * Year: 2026
 * Description: JavaScript functionality for the real estate chatbot interface
 */

class RealEstateChatBot {
    constructor() {
        this.chatMessages = document.getElementById('chatMessages');
        this.messageInput = document.getElementById('messageInput');
        this.typingIndicator = document.getElementById('typingIndicator');
        this.conversationHistory = [];
        this.isTyping = false;
        
        this.initializeEventListeners();
        this.loadConversationHistory();
    }
    
    initializeEventListeners() {
        // Message input events
        this.messageInput.addEventListener('keypress', (e) => {
            if (e.key === 'Enter' && !e.shiftKey) {
                e.preventDefault();
                this.sendMessage();
            }
        });
        
        // Auto-resize textarea
        this.messageInput.addEventListener('input', () => {
            this.autoResizeTextarea();
        });
        
        // Quick action buttons
        document.querySelectorAll('.quick-action-btn').forEach(btn => {
            btn.addEventListener('click', () => {
                const message = btn.textContent.trim();
                this.sendQuickMessage(message);
            });
        });
        
        // Window focus/blur events
        window.addEventListener('focus', () => {
            this.messageInput.focus();
        });
        
        // Keyboard shortcuts
        document.addEventListener('keydown', (e) => {
            if (e.ctrlKey && e.key === '/') {
                e.preventDefault();
                this.showHelp();
            }
        });
    }
    
    async sendMessage() {
        const message = this.messageInput.value.trim();
        
        if (!message || this.isTyping) return;
        
        // Add user message to chat
        this.addMessage(message, 'user');
        this.messageInput.value = '';
        this.autoResizeTextarea();
        
        // Show typing indicator
        this.showTypingIndicator();
        
        try {
            // Send message to backend
            const response = await fetch('/api/chat', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'X-CSRFToken': this.getCSRFToken()
                },
                body: JSON.stringify({
                    message: message,
                    conversation_history: this.conversationHistory.slice(-5) // Send last 5 messages for context
                })
            });
            
            const data = await response.json();
            
            this.hideTypingIndicator();
            
            if (data.success) {
                this.addMessage(data.response, 'bot');
                this.conversationHistory.push(
                    { role: 'user', content: message, timestamp: new Date().toISOString() },
                    { role: 'assistant', content: data.response, timestamp: new Date().toISOString() }
                );
                this.saveConversationHistory();
                
                // Process any special commands in the response
                this.processSpecialCommands(data);
            } else {
                this.addMessage('Sorry, I encountered an error. Please try again.', 'bot');
                console.error('Chat API Error:', data.error);
            }
            
        } catch (error) {
            this.hideTypingIndicator();
            this.addMessage('Connection error. Please check your internet connection and try again.', 'bot');
            console.error('Chat Connection Error:', error);
        }
    }
    
    sendQuickMessage(message) {
        this.messageInput.value = message;
        this.sendMessage();
    }
    
    addMessage(content, sender) {
        const messageDiv = document.createElement('div');
        messageDiv.className = `message ${sender}`;
        
        const messageBubble = document.createElement('div');
        messageBubble.className = 'message-bubble';
        
        // Process content for special formatting
        const processedContent = this.processMessageContent(content);
        messageBubble.innerHTML = processedContent;
        
        const messageTime = document.createElement('div');
        messageTime.className = 'message-time';
        messageTime.textContent = this.formatTime();
        
        messageDiv.appendChild(messageBubble);
        messageDiv.appendChild(messageTime);
        
        this.chatMessages.appendChild(messageDiv);
        this.scrollToBottom();
        
        // Add animation
        setTimeout(() => {
            messageDiv.classList.add('fade-in');
        }, 10);
    }
    
    processMessageContent(content) {
        // Convert markdown-like formatting to HTML
        let processed = content
            .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
            .replace(/\*(.*?)\*/g, '<em>$1</em>')
            .replace(/`(.*?)`/g, '<code>$1</code>')
            .replace(/\n\n/g, '</p><p>')
            .replace(/\n/g, '<br>');
        
        // Add paragraph tags
        if (processed.includes('<p>') || processed.includes('<br>')) {
            processed = `<p>${processed}</p>`;
        }
        
        // Convert emojis and icons
        processed = this.convertEmojis(processed);
        
        // Process property listings
        processed = this.processPropertyListings(processed);
        
        return processed;
    }
    
    convertEmojis(content) {
        const emojiMap = {
            '🏠': 'house',
            'πŸ“': 'map-marker-alt',
            'πŸ’°': 'rupee-sign',
            'πŸ›οΈ': 'bed',
            '🚿': 'bath',
            'πŸ“': 'ruler-combined',
            'πŸ“…': 'calendar',
            'πŸ’¬': 'comments',
            'πŸ”': 'search',
            '⭐': 'star',
            'βœ…': 'check-circle',
            '❌': 'times-circle'
        };
        
        Object.entries(emojiMap).forEach(([emoji, iconClass]) => {
            content = content.replace(
                new RegExp(emoji, 'g'),
                `<i class="fas fa-${iconClass}"></i>`
            );
        });
        
        return content;
    }
    
    processPropertyListings(content) {
        // Detect property listings and format them nicely
        const propertyRegex = /\d+\.\s*([^:]+):\s*([^πŸ“πŸ’°πŸ πŸ›οΈπŸšΏπŸ“]+)/g;
        
        return content.replace(propertyRegex, (match, title, details) => {
            return `
                <div class="property-listing">
                    <h6 class="property-title">${title}</h6>
                    <div class="property-details">${details}</div>
                </div>
            `;
        });
    }
    
    processSpecialCommands(data) {
        // Handle special commands from the bot response
        if (data.commands) {
            data.commands.forEach(command => {
                switch (command.type) {
                    case 'show_properties':
                        this.displayPropertyCards(command.properties);
                        break;
                    case 'schedule_appointment':
                        this.showAppointmentForm(command.property_id);
                        break;
                    case 'show_location':
                        this.displayMap(command.location);
                        break;
                }
            });
        }
    }
    
    displayPropertyCards(properties) {
        const propertiesContainer = document.createElement('div');
        propertiesContainer.className = 'properties-grid';
        propertiesContainer.style.cssText = 'display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 15px; margin: 20px 0;';
        
        properties.forEach(property => {
            const card = this.createPropertyCard(property);
            propertiesContainer.appendChild(card);
        });
        
        this.chatMessages.appendChild(propertiesContainer);
        this.scrollToBottom();
    }
    
    createPropertyCard(property) {
        const card = document.createElement('div');
        card.className = 'property-card card-hover';
        card.style.cssText = 'background: white; border-radius: 12px; padding: 15px; box-shadow: 0 4px 6px rgba(0,0,0,0.1);';
        
        card.innerHTML = `
            <div class="property-header">
                <h6 class="property-title" style="margin: 0 0 10px 0; color: #2c3e50; font-weight: 600;">${property.title}</h6>
                <div class="property-price" style="color: #3498db; font-size: 1.2rem; font-weight: 700; margin-bottom: 10px;">β‚Ή${property.price ? property.price.toLocaleString() : 'Price on request'}</div>
            </div>
            <div class="property-details">
                <div class="property-location" style="color: #666; margin-bottom: 10px;">
                    <i class="fas fa-map-marker-alt"></i> ${property.location}
                </div>
                <div class="property-features" style="display: flex; gap: 15px; margin-bottom: 10px;">
                    <span><i class="fas fa-bed"></i> ${property.bedrooms || 'N/A'} beds</span>
                    <span><i class="fas fa-bath"></i> ${property.bathrooms || 'N/A'} baths</span>
                    <span><i class="fas fa-ruler-combined"></i> ${property.area_sqft || 'N/A'} sqft</span>
                </div>
                <div class="property-actions" style="margin-top: 15px;">
                    <button class="btn-gradient" onclick="chatBot.viewPropertyDetails(${property.id})" style="padding: 8px 16px; font-size: 0.9rem;">
                        View Details
                    </button>
                    <button class="btn-gradient" onclick="chatBot.scheduleViewing(${property.id})" style="padding: 8px 16px; font-size: 0.9rem; margin-left: 10px;">
                        Schedule Viewing
                    </button>
                </div>
            </div>
        `;
        
        return card;
    }
    
    viewPropertyDetails(propertyId) {
        this.sendQuickMessage(`Tell me more about property ${propertyId}`);
    }
    
    scheduleViewing(propertyId) {
        this.sendQuickMessage(`Schedule a viewing for property ${propertyId}`);
    }
    
    showAppointmentForm(propertyId) {
        const formContainer = document.createElement('div');
        formContainer.className = 'appointment-form';
        formContainer.style.cssText = 'background: white; padding: 20px; border-radius: 12px; margin: 20px 0; box-shadow: 0 4px 6px rgba(0,0,0,0.1);';
        
        formContainer.innerHTML = `
            <h6 style="margin-bottom: 15px; color: #2c3e50;">Schedule Property Viewing</h6>
            <form id="appointmentForm">
                <div class="form-group" style="margin-bottom: 15px;">
                    <label class="form-label">Preferred Date</label>
                    <input type="date" class="form-control" id="viewingDate" required>
                </div>
                <div class="form-group" style="margin-bottom: 15px;">
                    <label class="form-label">Preferred Time</label>
                    <input type="time" class="form-control" id="viewingTime" required>
                </div>
                <div class="form-group" style="margin-bottom: 15px;">
                    <label class="form-label">Contact Number</label>
                    <input type="tel" class="form-control" id="contactNumber" placeholder="+91 93305 39277" required>
                </div>
                <div class="form-group" style="margin-bottom: 15px;">
                    <label class="form-label">Additional Notes</label>
                    <textarea class="form-control" id="viewingNotes" rows="3" placeholder="Any specific requirements or questions..."></textarea>
                </div>
                <div style="display: flex; gap: 10px;">
                    <button type="submit" class="btn-gradient">Schedule Viewing</button>
                    <button type="button" class="btn-gradient" onclick="this.closest('.appointment-form').remove()" style="background: #95a5a6;">Cancel</button>
                </div>
            </form>
        `;
        
        this.chatMessages.appendChild(formContainer);
        this.scrollToBottom();
        
        // Handle form submission
        formContainer.querySelector('#appointmentForm').addEventListener('submit', (e) => {
            e.preventDefault();
            this.submitAppointment(propertyId);
        });
        
        // Set minimum date to today
        const dateInput = formContainer.querySelector('#viewingDate');
        const today = new Date().toISOString().split('T')[0];
        dateInput.min = today;
    }
    
    async submitAppointment(propertyId) {
        const formData = {
            property_id: propertyId,
            date: document.getElementById('viewingDate').value,
            time: document.getElementById('viewingTime').value,
            contact: document.getElementById('contactNumber').value,
            notes: document.getElementById('viewingNotes').value
        };
        
        try {
            const response = await fetch('/api/appointments/schedule', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'X-CSRFToken': this.getCSRFToken()
                },
                body: JSON.stringify(formData)
            });
            
            const data = await response.json();
            
            if (data.success) {
                this.addMessage('Your viewing has been scheduled successfully! Our team will contact you shortly to confirm the appointment.', 'bot');
                document.querySelector('.appointment-form').remove();
            } else {
                this.addMessage('Sorry, there was an error scheduling your viewing. Please try again.', 'bot');
            }
        } catch (error) {
            this.addMessage('Connection error. Please try again.', 'bot');
            console.error('Appointment scheduling error:', error);
        }
    }
    
    displayMap(location) {
        const mapContainer = document.createElement('div');
        mapContainer.className = 'map-container';
        mapContainer.style.cssText = 'background: #f8f9fa; border-radius: 12px; padding: 20px; margin: 20px 0; text-align: center;';
        
        mapContainer.innerHTML = `
            <h6 style="margin-bottom: 15px; color: #2c3e50;">πŸ“ Location: ${location}</h6>
            <div style="background: #e9ecef; height: 200px; border-radius: 8px; display: flex; align-items: center; justify-content: center; color: #6c757d;">
                <div>
                    <i class="fas fa-map-marked-alt" style="font-size: 3rem; margin-bottom: 10px;"></i>
                    <p>Interactive map would be displayed here</p>
                    <small>Integration with Google Maps or similar service</small>
                </div>
            </div>
        `;
        
        this.chatMessages.appendChild(mapContainer);
        this.scrollToBottom();
    }
    
    showTypingIndicator() {
        this.isTyping = true;
        this.typingIndicator.style.display = 'block';
        this.scrollToBottom();
    }
    
    hideTypingIndicator() {
        this.isTyping = false;
        this.typingIndicator.style.display = 'none';
    }
    
    scrollToBottom() {
        this.chatMessages.scrollTop = this.chatMessages.scrollHeight;
    }
    
    formatTime() {
        return new Date().toLocaleTimeString('en-US', { 
            hour: '2-digit', 
            minute: '2-digit' 
        });
    }
    
    autoResizeTextarea() {
        if (this.messageInput.tagName === 'TEXTAREA') {
            this.messageInput.style.height = 'auto';
            this.messageInput.style.height = Math.min(this.messageInput.scrollHeight, 120) + 'px';
        }
    }
    
    getCSRFToken() {
        const token = document.querySelector('meta[name="csrf-token"]');
        return token ? token.getAttribute('content') : '';
    }
    
    saveConversationHistory() {
        try {
            localStorage.setItem('realEstateBotHistory', JSON.stringify(this.conversationHistory));
        } catch (error) {
            console.warn('Could not save conversation history:', error);
        }
    }
    
    loadConversationHistory() {
        try {
            const saved = localStorage.getItem('realEstateBotHistory');
            if (saved) {
                this.conversationHistory = JSON.parse(saved);
            }
        } catch (error) {
            console.warn('Could not load conversation history:', error);
        }
    }
    
    clearConversationHistory() {
        this.conversationHistory = [];
        localStorage.removeItem('realEstateBotHistory');
        this.chatMessages.innerHTML = '';
        this.addMessage('Conversation history cleared. How can I help you today?', 'bot');
    }
    
    showHelp() {
        const helpMessage = `
**Available Commands:**
β€’ Search for properties by location, price, type
β€’ Schedule property viewings
β€’ Get property details and information
β€’ Ask about neighborhoods and locations
β€’ Request property recommendations

**Examples:**
β€’ "Show me apartments in Mumbai under 50 lakhs"
β€’ "Schedule a viewing for property 123"
β€’ "Tell me about the 3BHK house in Delhi"
β€’ "What amenities are available in the Bangalore property?"

**Keyboard Shortcuts:**
β€’ Ctrl+/: Show this help message
β€’ Enter: Send message
β€’ Shift+Enter: New line

Need more help? Contact us at info@rskworld.com or +91 93305 39277
        `;
        
        this.addMessage(helpMessage, 'bot');
    }
    
    exportConversation() {
        const conversationText = this.conversationHistory
            .map(msg => `[${msg.timestamp}] ${msg.role.toUpperCase()}: ${msg.content}`)
            .join('\n\n');
        
        const blob = new Blob([conversationText], { type: 'text/plain' });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = `real-estate-bot-conversation-${new Date().toISOString().split('T')[0]}.txt`;
        a.click();
        URL.revokeObjectURL(url);
    }
}

// Initialize the chat bot when DOM is ready
document.addEventListener('DOMContentLoaded', () => {
    window.chatBot = new RealEstateChatBot();
    
    // Add some global functions for backward compatibility
    window.sendMessage = () => window.chatBot.sendMessage();
    window.sendQuickMessage = (msg) => window.chatBot.sendQuickMessage(msg);
    
    // Show welcome message after a short delay
    setTimeout(() => {
        window.chatBot.addMessage('Welcome to Real Estate Bot! 🏠 I can help you find your dream property, schedule viewings, and answer all your real estate questions. What are you looking for today?', 'bot');
    }, 500);
});

// Service Worker for offline functionality (optional)
if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('/static/js/sw.js')
        .then(registration => console.log('SW registered'))
        .catch(error => console.log('SW registration failed'));
}
501 linesβ€’19.4 KB
javascript
πŸš€ 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