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
/
static
/
js
RSK World
real-estate-bot
Real Estate Bot - Python + Flask + OpenAI + SQLite + Property Search + AI Chatbot + Viewing Scheduler
js
  • advanced-features.js17.2 KB
  • chat.js19.4 KB
README.mdchat.js
README.md
Raw Download

README.md

# Real Estate Bot

**AI-Powered Real Estate Assistant**

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 Bot is an intelligent chatbot application designed to help users search for properties, schedule viewings, and get comprehensive information about real estate listings. Built with Python, Flask, and OpenAI API, this bot provides a conversational interface for property discovery and management.

## ✨ Features

- **πŸ” Property Search**: Find properties based on location, price range, property type, bedrooms, and other criteria
- **πŸ“… Viewing Scheduling**: Schedule property viewings with preferred dates and times
- **πŸ’¬ Property Inquiries**: Get detailed information about specific properties
- **πŸ“ Location Information**: Learn about neighborhoods and areas
- **πŸ€– AI-Powered Chat**: Natural language processing with OpenAI GPT
- **πŸ’Ύ Database Management**: SQLite database for properties, appointments, and user data
- **🌐 Web Interface**: Modern, responsive web UI with real-time chat
- **πŸ“± Mobile Friendly**: Fully responsive design for all devices

## πŸ› οΈ Technologies Used

- **Backend**: Python 3.8+, Flask
- **AI/ML**: OpenAI GPT API
- **Database**: SQLite
- **Frontend**: HTML5, CSS3, JavaScript (ES6+)
- **UI Framework**: Bootstrap 5
- **Icons**: Font Awesome
- **HTTP Client**: Requests
- **Environment Management**: python-dotenv

## πŸ“‹ Requirements

- Python 3.8 or higher
- pip package manager
- OpenAI API key
- Modern web browser

## πŸš€ Installation

1. **Clone the repository**
```bash
git clone <repository-url>
cd real-estate-bot
```

2. **Create virtual environment**
```bash
python -m venv venv

# Windows
venv\Scripts\activate

# macOS/Linux
source venv/bin/activate
```

3. **Install dependencies**
```bash
pip install -r requirements.txt
```

4. **Set up environment variables**
```bash
cp .env.example .env
```

Edit `.env` file and add your API keys:
```env
OPENAI_API_KEY=your_openai_api_key_here
SECRET_KEY=your_secret_key_here
```

5. **Initialize the database**
The database will be automatically created when you run the application for the first time.

## πŸƒβ€β™‚οΈ Running the Application

1. **Start the Flask application**
```bash
python src/app.py
```

2. **Open your web browser**
Navigate to `http://localhost:5000`

3. **Start chatting!**
The bot will be ready to help you find properties and answer your real estate questions.

## πŸ“ Project Structure

```
real-estate-bot/
β”œβ”€β”€ src/
β”‚ β”œβ”€β”€ app.py # Main Flask application
β”‚ β”œβ”€β”€ chatbot.py # Chatbot logic and AI integration
β”‚ β”œβ”€β”€ database.py # Database management
β”‚ └── property_search.py # Property search engine
β”œβ”€β”€ templates/
β”‚ └── index.html # Main web interface
β”œβ”€β”€ static/
β”‚ β”œβ”€β”€ css/
β”‚ β”‚ └── style.css # Custom styles
β”‚ └── js/
β”‚ └── chat.js # Frontend JavaScript
β”œβ”€β”€ data/
β”‚ └── real_estate_bot.db # SQLite database
β”œβ”€β”€ tests/
β”‚ └── test_*.py # Unit tests
β”œβ”€β”€ requirements.txt # Python dependencies
β”œβ”€β”€ .env # Environment variables
└── README.md # This file
```

## πŸ’¬ Usage Examples

### Property Search
- "Show me apartments in Mumbai under 50 lakhs"
- "Find 3-bedroom houses in Delhi"
- "I'm looking for a 2BHK flat in Bangalore with parking"

### Schedule Viewings
- "Schedule a viewing for property 123"
- "I want to visit the apartment in Pune tomorrow"
- "Book an appointment for the house in Chennai"

### Property Information
- "Tell me about property 456"
- "What's the price of the 3BHK in Mumbai?"
- "What amenities are available in the Bangalore property?"

### Location Queries
- "Tell me about the neighborhood in Delhi"
- "What schools are near the property in Pune?"
- "How is the connectivity in Mumbai?"

## πŸ”§ Configuration

### Environment Variables

- `OPENAI_API_KEY`: Your OpenAI API key (required)
- `SECRET_KEY`: Flask secret key for sessions
- `DATABASE_URL`: Database connection URL (default: SQLite)
- `REAL_ESTATE_API_KEY`: External real estate API key (optional)
- `REAL_ESTATE_API_URL`: External real estate API URL (optional)

### Database Schema

The application uses SQLite with the following tables:

- **properties**: Property listings and details
- **users**: User information and preferences
- **appointments**: Scheduled property viewings
- **inquiries**: Property-related inquiries
- **chat_history**: Conversation logs

## πŸ§ͺ Testing

Run the test suite:
```bash
python -m pytest tests/
```

Or run individual tests:
```bash
python -m pytest tests/test_chatbot.py
python -m pytest tests/test_database.py
python -m pytest tests/test_property_search.py
```

## πŸ”Œ API Endpoints

### Chat API
- `POST /api/chat` - Send message to chatbot
- `GET /api/chat/history` - Get conversation history

### Property API
- `POST /api/properties/search` - Search properties
- `GET /api/properties/<id>` - Get property details
- `GET /api/properties/<id>/similar` - Get similar properties

### Appointment API
- `POST /api/appointments/schedule` - Schedule viewing
- `GET /api/appointments/<user_id>` - Get user appointments

### Inquiry API
- `POST /api/inquiries/submit` - Submit property inquiry

## 🎨 Customization

### Adding New Property Types
Edit the `property_types` dictionary in `src/chatbot.py` to add new property types and keywords.

### Modifying Search Criteria
Update the search logic in `src/property_search.py` to add new search filters and criteria.

### Customizing UI
Modify the HTML templates and CSS files in the `templates/` and `static/css/` directories.

## πŸš€ Deployment

### Production Deployment with Gunicorn
```bash
pip install gunicorn
gunicorn -w 4 -b 0.0.0.0:5000 src.app:app
```

### Docker Deployment
```dockerfile
FROM python:3.9-slim

WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt

COPY . .
EXPOSE 5000

CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:5000", "src.app:app"]
```

### Environment Variables for Production
- Set `FLASK_ENV=production`
- Use a strong `SECRET_KEY`
- Configure proper database connections
- Set up proper logging

## πŸ”’ Security Considerations

- Keep your OpenAI API key secure and never commit it to version control
- Use environment variables for sensitive configuration
- Implement rate limiting for API endpoints
- Validate and sanitize all user inputs
- Use HTTPS in production
- Regularly update dependencies

## 🀝 Contributing

1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request

## πŸ“ License

This project is licensed under the MIT License - see the LICENSE file for details.

## πŸ“ž Support

For support and inquiries:

- **Email**: info@rskworld.com
- **Phone**: +91 93305 39277
- **Website**: https://rskworld.in
- **Support**: support@rskworld.com

## πŸ™ Acknowledgments

- OpenAI for the powerful GPT API
- Flask team for the excellent web framework
- Bootstrap for the responsive UI components
- Font Awesome for the beautiful icons

---

**Β© 2026 RSK World. All rights reserved.**

*Developed by Molla Samser*
*Designed & Tested by Rima Khatun*

*Content used for educational purposes only. View [Disclaimer](https://rskworld.in/disclaimer.php)*
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