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
fitness-coach-bot
/
templates
RSK World
fitness-coach-bot
Fitness Coach Bot - Python + Flask + SQLAlchemy + Workout Plans + Exercise Guidance + Health Tracking + AI Fitness Coach
templates
  • index.html17.3 KB
RELEASE_NOTES_v1.0.0.mdfitness_coach.dbfitness_models.pyworkout_buddy_matcher.pyvoice_recognition.js
RELEASE_NOTES_v1.0.0.md
Raw Download

RELEASE_NOTES_v1.0.0.md

# Release Notes - Version 1.0.0

**Release Date:** January 2026
**Repository:** https://github.com/rskworld/fitness-coach-bot
**Tag:** v1.0.0

---

## 🎉 Initial Release

This is the first official release of the Fitness Coach Bot - an AI-powered comprehensive fitness coaching chatbot application.

---

## ✨ Features

### Core Features
- **AI-Powered Chatbot**: Intelligent fitness coaching chatbot that provides personalized advice
- **Personalized Workout Generation**: AI-driven workout plans based on user profile and goals
- **Nutrition Analysis**: Food image analysis and meal planning recommendations
- **Progress Tracking**: Comprehensive workout and fitness progress tracking
- **User Profiles**: Detailed user profile management with fitness goals

### Advanced Features
- **Social Features**: Create fitness challenges, join teams, share progress, and connect with workout buddies
- **Gamification System**: Achievements, levels, badges, leaderboards, and rewards
- **Advanced Analytics**: Detailed fitness analytics with trends, predictions, and insights
- **Wearable Integration**: Support for wearable devices (Fitbit, Apple Watch, Garmin, etc.)
- **Voice Coaching**: Voice command processing and workout guidance
- **Pose Detection**: Real-time exercise form analysis and correction
- **Smart Recovery**: Recovery score calculation and activity recommendations
- **Workout Buddy Matching**: Find and connect with compatible workout partners

### Technical Features
- **RESTful API**: Comprehensive REST API with 20+ endpoints
- **Modern UI**: Responsive Bootstrap 5 interface with real-time updates
- **Database**: SQLAlchemy ORM with SQLite database
- **Real-time Chat**: Interactive chat interface with message history
- **Health Tips**: Dynamic health and fitness tips display

---

## 🛠️ Technical Stack

- **Backend**: Flask 2.3.3, Python 3.13
- **Database**: SQLAlchemy 2.0.45, SQLite
- **Frontend**: Bootstrap 5, Vanilla JavaScript, Chart.js
- **AI/ML**: NumPy, OpenAI integration ready
- **Dependencies**: See `requirements.txt`

---

## 📦 Installation

### Prerequisites
- Python 3.13 or higher
- pip package manager

### Setup Steps

1. **Clone the repository**:
```bash
git clone https://github.com/rskworld/fitness-coach-bot.git
cd fitness-coach-bot
```

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

3. **Initialize database**:
```bash
python init_db.py
```

4. **Run the application**:
```bash
python app.py
```

5. **Access the application**:
- Open your browser and navigate to: `http://localhost:5000`

---

## 📋 API Endpoints

### Chat & Core
- `POST /api/chat` - Chat with fitness coach
- `GET /api/workout-plans` - Get workout plans
- `GET /api/exercises` - Get exercises
- `POST /api/progress` - Save workout progress
- `GET /api/health-tips` - Get health tips
- `GET/POST /api/user/profile` - User profile management

### Advanced Features
- `POST /api/ai-workout` - Generate AI workout
- `POST /api/nutrition-analyze` - Analyze nutrition
- `POST /api/social-challenge` - Create challenge
- `GET /api/analytics` - Get analytics
- `GET /api/gamification/profile` - Gamification stats
- `POST /api/wearable/connect` - Connect wearable
- `POST /api/wearable/sync/<device_id>` - Sync wearable
- `POST /api/voice/command` - Process voice command
- `POST /api/voice/workout-guidance` - Get workout guidance
- `GET/POST /api/buddy/profile` - Workout buddy profile
- `GET /api/buddy/find-matches` - Find workout buddies
- `POST /api/buddy/request` - Send buddy request
- `POST /api/recovery/calculate` - Calculate recovery
- `GET /api/recovery/activities` - Get recovery activities
- `POST /api/pose-workout` - Save pose workout data

---

## 🐛 Bug Fixes & Improvements

### Fixed Issues
- ✅ Fixed SQLAlchemy compatibility issue with Python 3.13
- ✅ Updated all dependencies to compatible versions
- ✅ Fixed datetime timezone issues in models
- ✅ Verified all imports and syntax
- ✅ Added proper `.gitignore` file
- ✅ Created comprehensive documentation

### Improvements
- ✅ Optimized database models
- ✅ Enhanced error handling
- ✅ Improved code organization
- ✅ Added comprehensive docstrings
- ✅ Created release notes and documentation

---

## 📁 Project Structure

```
fitness-coach-bot/
├── app.py # Main Flask application
├── config.py # Configuration settings
├── init_db.py # Database initialization
├── demo_data.py # Demo data generator
├── requirements.txt # Python dependencies
├── models/ # Database models
│ ├── __init__.py
│ └── fitness_models.py
├── utils/ # Utility modules
│ ├── __init__.py
│ ├── fitness_coach.py
│ ├── ai_workout_generator.py
│ ├── nutrition_ai.py
│ ├── social_features.py
│ ├── analytics_engine.py
│ ├── gamification_system.py
│ ├── wearable_integration.py
│ ├── voice_coach.py
│ ├── workout_buddy_matcher.py
│ └── smart_recovery.py
├── templates/ # HTML templates
│ └── index.html
├── static/ # Static files
│ ├── css/
│ │ ├── style.css
│ │ └── advanced-features.css
│ └── js/
│ ├── app.js
│ ├── voice_recognition.js
│ ├── pose_detection.js
│ └── analytics_dashboard.js
├── README.md # Main documentation
├── ADVANCED_FEATURES.md # Advanced features documentation
└── LICENSE # License file
```

---

## 👥 Credits

**Author:** RSK World
**Website:** https://rskworld.in
**Founder:** Molla Samser
**Designer & Tester:** Rima Khatun
**Contact:** help@rskworld.in, +91 93305 39277
**Year:** 2026

---

## 📄 License

This project is part of RSK World's free programming resources. Content used for educational purposes only.

---

## 🔗 Links

- **Repository:** https://github.com/rskworld/fitness-coach-bot
- **Website:** https://rskworld.in
- **Issues:** https://github.com/rskworld/fitness-coach-bot/issues

---

## 🚀 Next Steps

- Set up environment variables for production
- Configure database for production use
- Add OpenAI API key for enhanced AI features
- Deploy to production server
- Set up CI/CD pipeline

---

## 📝 Changelog

### v1.0.0 (2026-01-10)
- Initial release
- Complete fitness coaching application
- All core and advanced features implemented
- Python 3.13 compatibility verified
- All dependencies updated and tested

---

**Thank you for using Fitness Coach Bot!** 💪
fitness_coach.db

This file cannot be displayed in the browser.

Download File
models/fitness_models.py
Raw Download
Find: Go to:
"""
Fitness Coach Bot - Database Models
Author: RSK World (https://rskworld.in)
Founded by: Molla Samser
Designer & Tester: Rima Khatun
Contact: help@rskworld.in, +91 93305 39277
Year: 2026
"""

from flask_sqlalchemy import SQLAlchemy
from datetime import datetime, timezone

# db instance will be initialized in app.py and imported here
db = SQLAlchemy()

class User(db.Model):
    """User model for storing user information and fitness goals"""
    __tablename__ = 'users'
    
    id = db.Column(db.String(50), primary_key=True)
    name = db.Column(db.String(100))
    email = db.Column(db.String(120))
    age = db.Column(db.Integer)
    weight = db.Column(db.Float)  # in kg
    height = db.Column(db.Float)  # in cm
    fitness_goal = db.Column(db.String(100))  # weight_loss, muscle_gain, endurance, etc.
    activity_level = db.Column(db.String(50))  # sedentary, light, moderate, active, very_active
    medical_conditions = db.Column(db.Text)
    created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
    updated_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc))
    
    # Relationships
    progress = db.relationship('Progress', backref='user', lazy=True)
    
    def to_dict(self):
        return {
            'id': self.id,
            'name': self.name,
            'email': self.email,
            'age': self.age,
            'weight': self.weight,
            'height': self.height,
            'fitness_goal': self.fitness_goal,
            'activity_level': self.activity_level,
            'medical_conditions': self.medical_conditions,
            'created_at': self.created_at.isoformat() if self.created_at else None,
            'updated_at': self.updated_at.isoformat() if self.updated_at else None
        }

class WorkoutPlan(db.Model):
    """Workout plan model for storing predefined workout routines"""
    __tablename__ = 'workout_plans'
    
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), nullable=False)
    description = db.Column(db.Text)
    difficulty = db.Column(db.String(20))  # beginner, intermediate, advanced
    duration_weeks = db.Column(db.Integer)
    target_goal = db.Column(db.String(50))  # weight_loss, muscle_gain, strength, etc.
    equipment_needed = db.Column(db.Text)
    category = db.Column(db.String(50))  # full_body, upper_body, lower_body, cardio, etc.
    created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
    
    # Relationships
    exercises = db.relationship('WorkoutExercise', backref='workout_plan', lazy=True)
    
    def to_dict(self):
        return {
            'id': self.id,
            'name': self.name,
            'description': self.description,
            'difficulty': self.difficulty,
            'duration_weeks': self.duration_weeks,
            'target_goal': self.target_goal,
            'equipment_needed': self.equipment_needed,
            'category': self.category,
            'created_at': self.created_at.isoformat() if self.created_at else None,
            'exercises': [we.exercise.to_dict() for we in self.exercises]
        }

class Exercise(db.Model):
    """Exercise model for storing individual exercise information"""
    __tablename__ = 'exercises'
    
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), nullable=False)
    description = db.Column(db.Text)
    category = db.Column(db.String(50))  # strength, cardio, flexibility, balance
    muscle_group = db.Column(db.String(50))  # chest, back, legs, shoulders, arms, core
    equipment = db.Column(db.String(100))
    difficulty = db.Column(db.String(20))  # beginner, intermediate, advanced
    instructions = db.Column(db.Text)
    tips = db.Column(db.Text)
    calories_per_minute = db.Column(db.Float)
    video_url = db.Column(db.String(255))
    image_url = db.Column(db.String(255))
    created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
    
    # Relationships
    workout_exercises = db.relationship('WorkoutExercise', backref='exercise', lazy=True)
    progress = db.relationship('Progress', backref='exercise', lazy=True)
    
    def to_dict(self):
        return {
            'id': self.id,
            'name': self.name,
            'description': self.description,
            'category': self.category,
            'muscle_group': self.muscle_group,
            'equipment': self.equipment,
            'difficulty': self.difficulty,
            'instructions': self.instructions,
            'tips': self.tips,
            'calories_per_minute': self.calories_per_minute,
            'video_url': self.video_url,
            'image_url': self.image_url,
            'created_at': self.created_at.isoformat() if self.created_at else None
        }

class WorkoutExercise(db.Model):
    """Junction table for workout plans and exercises"""
    __tablename__ = 'workout_exercises'
    
    id = db.Column(db.Integer, primary_key=True)
    workout_plan_id = db.Column(db.Integer, db.ForeignKey('workout_plans.id'), nullable=False)
    exercise_id = db.Column(db.Integer, db.ForeignKey('exercises.id'), nullable=False)
    day_of_week = db.Column(db.Integer)  # 1-7 for Monday-Sunday
    sets = db.Column(db.Integer)
    reps = db.Column(db.Integer)
    duration_seconds = db.Column(db.Integer)
    rest_seconds = db.Column(db.Integer)
    order = db.Column(db.Integer)
    
    def to_dict(self):
        return {
            'id': self.id,
            'workout_plan_id': self.workout_plan_id,
            'exercise_id': self.exercise_id,
            'day_of_week': self.day_of_week,
            'sets': self.sets,
            'reps': self.reps,
            'duration_seconds': self.duration_seconds,
            'rest_seconds': self.rest_seconds,
            'order': self.order,
            'exercise': self.exercise.to_dict() if self.exercise else None
        }

class Progress(db.Model):
    """Progress model for tracking user workout progress"""
    __tablename__ = 'progress'
    
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.String(50), db.ForeignKey('users.id'), nullable=False)
    exercise_id = db.Column(db.Integer, db.ForeignKey('exercises.id'), nullable=False)
    sets_completed = db.Column(db.Integer)
    reps_completed = db.Column(db.Integer)
    weight_used = db.Column(db.Float)  # weight lifted in kg
    duration_seconds = db.Column(db.Integer)
    calories_burned = db.Column(db.Float)
    notes = db.Column(db.Text)
    date = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
    
    def to_dict(self):
        return {
            'id': self.id,
            'user_id': self.user_id,
            'exercise_id': self.exercise_id,
            'sets_completed': self.sets_completed,
            'reps_completed': self.reps_completed,
            'weight_used': self.weight_used,
            'duration_seconds': self.duration_seconds,
            'calories_burned': self.calories_burned,
            'notes': self.notes,
            'date': self.date.isoformat() if self.date else None,
            'exercise': self.exercise.to_dict() if self.exercise else None
        }

class HealthTip(db.Model):
    """Health tips model for storing fitness and nutrition advice"""
    __tablename__ = 'health_tips'
    
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(200), nullable=False)
    content = db.Column(db.Text, nullable=False)
    category = db.Column(db.String(50))  # nutrition, exercise, recovery, motivation, safety
    author = db.Column(db.String(100))
    source_url = db.Column(db.String(255))
    is_featured = db.Column(db.Boolean, default=False)
    created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
    updated_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc))
    
    def to_dict(self):
        return {
            'id': self.id,
            'title': self.title,
            'content': self.content,
            'category': self.category,
            'author': self.author,
            'source_url': self.source_url,
            'is_featured': self.is_featured,
            'created_at': self.created_at.isoformat() if self.created_at else None,
            'updated_at': self.updated_at.isoformat() if self.updated_at else None
        }
204 lines•8.5 KB
python
utils/workout_buddy_matcher.py
Raw Download
Find: Go to:
"""
Workout Buddy Matching System
Author: RSK World (https://rskworld.in)
Founded by: Molla Samser
Designer & Tester: Rima Khatun
Contact: help@rskworld.in, +91 93305 39277
Year: 2026
"""

import json
from datetime import datetime, timedelta
from typing import Dict, List, Optional, Tuple
from dataclasses import dataclass

@dataclass
class WorkoutBuddy:
    user_id: str
    name: str
    fitness_level: str
    goals: List[str]
    preferred_workout_time: str
    location: Optional[str] = None
    preferred_activities: List[str] = None
    availability: Dict = None
    compatibility_score: float = 0.0

class WorkoutBuddyMatcher:
    """AI-powered workout buddy matching system"""
    
    def __init__(self):
        self.buddy_profiles = {}
        self.active_matches = {}
        
    def create_buddy_profile(self, user_data: Dict) -> Dict:
        """Create or update buddy matching profile"""
        profile = WorkoutBuddy(
            user_id=user_data.get('user_id'),
            name=user_data.get('name', 'User'),
            fitness_level=user_data.get('fitness_level', 'beginner'),
            goals=user_data.get('goals', []),
            preferred_workout_time=user_data.get('preferred_workout_time', 'morning'),
            location=user_data.get('location'),
            preferred_activities=user_data.get('preferred_activities', []),
            availability=user_data.get('availability', {})
        )
        
        self.buddy_profiles[profile.user_id] = profile
        
        return {
            'success': True,
            'profile': self._profile_to_dict(profile),
            'message': 'Buddy profile created successfully'
        }
    
    def find_matches(self, user_id: str, limit: int = 5) -> List[Dict]:
        """Find compatible workout buddies"""
        if user_id not in self.buddy_profiles:
            return []
        
        user_profile = self.buddy_profiles[user_id]
        matches = []
        
        for buddy_id, buddy_profile in self.buddy_profiles.items():
            if buddy_id == user_id:
                continue
            
            # Calculate compatibility score
            score = self._calculate_compatibility(user_profile, buddy_profile)
            
            if score > 0.5:  # Minimum compatibility threshold
                buddy_profile.compatibility_score = score
                matches.append({
                    'buddy': self._profile_to_dict(buddy_profile),
                    'compatibility_score': round(score * 100, 1),
                    'match_reasons': self._get_match_reasons(user_profile, buddy_profile)
                })
        
        # Sort by compatibility score
        matches.sort(key=lambda x: x['compatibility_score'], reverse=True)
        
        return matches[:limit]
    
    def _calculate_compatibility(self, user: WorkoutBuddy, buddy: WorkoutBuddy) -> float:
        """Calculate compatibility score between two users"""
        score = 0.0
        factors = 0
        
        # Fitness level compatibility (0.3 weight)
        level_match = self._match_fitness_level(user.fitness_level, buddy.fitness_level)
        score += level_match * 0.3
        factors += 0.3
        
        # Goals compatibility (0.25 weight)
        goals_match = self._match_goals(user.goals, buddy.goals)
        score += goals_match * 0.25
        factors += 0.25
        
        # Workout time compatibility (0.2 weight)
        time_match = 1.0 if user.preferred_workout_time == buddy.preferred_workout_time else 0.5
        score += time_match * 0.2
        factors += 0.2
        
        # Activity preferences (0.15 weight)
        activity_match = self._match_activities(user.preferred_activities, buddy.preferred_activities)
        score += activity_match * 0.15
        factors += 0.15
        
        # Location proximity (0.1 weight) - if both have location
        if user.location and buddy.location:
            location_match = self._calculate_location_proximity(user.location, buddy.location)
            score += location_match * 0.1
            factors += 0.1
        
        # Normalize score
        return score / factors if factors > 0 else 0.0
    
    def _match_fitness_level(self, level1: str, level2: str) -> float:
        """Match fitness levels"""
        levels = {'beginner': 1, 'intermediate': 2, 'advanced': 3}
        level1_num = levels.get(level1.lower(), 2)
        level2_num = levels.get(level2.lower(), 2)
        
        diff = abs(level1_num - level2_num)
        if diff == 0:
            return 1.0
        elif diff == 1:
            return 0.7  # Adjacent levels are somewhat compatible
        else:
            return 0.3  # Too far apart
    
    def _match_goals(self, goals1: List[str], goals2: List[str]) -> float:
        """Match fitness goals"""
        if not goals1 or not goals2:
            return 0.5  # Neutral if no goals specified
        
        common_goals = set(g.lower() for g in goals1) & set(g.lower() for g in goals2)
        all_goals = set(g.lower() for g in goals1) | set(g.lower() for g in goals2)
        
        if not all_goals:
            return 0.5
        
        return len(common_goals) / len(all_goals)
    
    def _match_activities(self, activities1: List[str], activities2: List[str]) -> float:
        """Match preferred activities"""
        if not activities1 or not activities2:
            return 0.5
        
        common = set(a.lower() for a in activities1) & set(a.lower() for a in activities2)
        total = len(set(a.lower() for a in activities1) | set(a.lower() for a in activities2))
        
        if total == 0:
            return 0.5
        
        return len(common) / total
    
    def _calculate_location_proximity(self, loc1: str, loc2: str) -> float:
        """Calculate location proximity (simplified)"""
        # In real implementation, would use geocoding API
        # For now, simple string matching
        if loc1.lower() == loc2.lower():
            return 1.0
        
        # Check if same city (simple check)
        loc1_parts = loc1.lower().split(',')
        loc2_parts = loc2.lower().split(',')
        
        if len(loc1_parts) > 0 and len(loc2_parts) > 0:
            if loc1_parts[0] == loc2_parts[0]:
                return 0.7  # Same city
        
        return 0.3  # Different locations
    
    def _get_match_reasons(self, user: WorkoutBuddy, buddy: WorkoutBuddy) -> List[str]:
        """Get reasons why users are matched"""
        reasons = []
        
        if user.fitness_level == buddy.fitness_level:
            reasons.append(f"Same fitness level: {user.fitness_level}")
        
        common_goals = set(g.lower() for g in user.goals) & set(g.lower() for g in buddy.goals)
        if common_goals:
            reasons.append(f"Shared goals: {', '.join(list(common_goals)[:2])}")
        
        if user.preferred_workout_time == buddy.preferred_workout_time:
            reasons.append(f"Same workout time preference: {user.preferred_workout_time}")
        
        common_activities = set(a.lower() for a in user.preferred_activities or []) & \
                           set(a.lower() for a in buddy.preferred_activities or [])
        if common_activities:
            reasons.append(f"Similar interests: {', '.join(list(common_activities)[:2])}")
        
        return reasons if reasons else ["Potential workout buddy"]
    
    def create_buddy_request(self, from_user_id: str, to_user_id: str, message: Optional[str] = None) -> Dict:
        """Send workout buddy request"""
        request = {
            'id': f"buddy_req_{datetime.now().strftime('%Y%m%d_%H%M%S')}_{from_user_id}",
            'from_user_id': from_user_id,
            'to_user_id': to_user_id,
            'message': message or "Would you like to be workout buddies?",
            'status': 'pending',
            'created_at': datetime.now().isoformat()
        }
        
        return {
            'success': True,
            'request': request,
            'message': 'Buddy request sent successfully'
        }
    
    def accept_buddy_request(self, request_id: str) -> Dict:
        """Accept buddy request"""
        return {
            'success': True,
            'message': 'Buddy request accepted! You are now workout buddies.',
            'match': {
                'created_at': datetime.now().isoformat(),
                'status': 'active'
            }
        }
    
    def suggest_group_workout(self, user_ids: List[str], workout_data: Dict) -> Dict:
        """Suggest group workout for matched buddies"""
        return {
            'success': True,
            'suggestion': {
                'workout_type': workout_data.get('type', 'group_training'),
                'suggested_time': workout_data.get('time'),
                'participants': user_ids,
                'message': 'Group workout suggestion created',
                'created_at': datetime.now().isoformat()
            }
        }
    
    def _profile_to_dict(self, profile: WorkoutBuddy) -> Dict:
        """Convert profile to dictionary"""
        return {
            'user_id': profile.user_id,
            'name': profile.name,
            'fitness_level': profile.fitness_level,
            'goals': profile.goals,
            'preferred_workout_time': profile.preferred_workout_time,
            'location': profile.location,
            'preferred_activities': profile.preferred_activities or [],
            'availability': profile.availability or {}
        }
248 lines•9.5 KB
python
static/js/voice_recognition.js
Raw Download
Find: Go to:
/**
 * Voice Recognition for Hands-Free Workouts
 * Author: RSK World (https://rskworld.in)
 * Founded by: Molla Samser
 * Designer & Tester: Rima Khatun
 * Contact: help@rskworld.in, +91 93305 39277
 * Year: 2026
 */

class VoiceRecognition {
    constructor() {
        this.recognition = null;
        this.isListening = false;
        this.onResultCallback = null;
        this.init();
    }

    init() {
        // Check for browser support
        const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
        
        if (!SpeechRecognition) {
            console.warn('Speech recognition not supported in this browser');
            this.showUnsupportedMessage();
            return;
        }

        this.recognition = new SpeechRecognition();
        this.recognition.continuous = false;
        this.recognition.interimResults = false;
        this.recognition.lang = 'en-US';

        this.recognition.onresult = (event) => {
            const transcript = event.results[0][0].transcript;
            if (this.onResultCallback) {
                this.onResultCallback(transcript);
            }
        };

        this.recognition.onerror = (event) => {
            console.error('Speech recognition error:', event.error);
            this.handleError(event.error);
        };

        this.recognition.onend = () => {
            this.isListening = false;
            this.updateUI();
        };
    }

    startListening(callback) {
        if (!this.recognition) {
            alert('Voice recognition not supported in your browser');
            return;
        }

        if (this.isListening) {
            this.stopListening();
            return;
        }

        this.onResultCallback = callback;
        this.isListening = true;
        
        try {
            this.recognition.start();
            this.updateUI();
            this.showListeningIndicator();
        } catch (error) {
            console.error('Error starting recognition:', error);
        }
    }

    stopListening() {
        if (this.recognition && this.isListening) {
            this.recognition.stop();
            this.isListening = false;
            this.updateUI();
            this.hideListeningIndicator();
        }
    }

    updateUI() {
        const button = document.getElementById('voiceToggleButton');
        if (button) {
            if (this.isListening) {
                button.innerHTML = '<i class="fas fa-microphone-slash"></i> Stop Listening';
                button.classList.add('btn-danger');
                button.classList.remove('btn-primary');
            } else {
                button.innerHTML = '<i class="fas fa-microphone"></i> Voice Command';
                button.classList.add('btn-primary');
                button.classList.remove('btn-danger');
            }
        }
    }

    showListeningIndicator() {
        let indicator = document.getElementById('voiceListeningIndicator');
        if (!indicator) {
            indicator = document.createElement('div');
            indicator.id = 'voiceListeningIndicator';
            indicator.className = 'voice-listening-indicator';
            indicator.innerHTML = `
                <div class="listening-pulse"></div>
                <p>Listening...</p>
            `;
            document.body.appendChild(indicator);
        }
        indicator.style.display = 'block';
    }

    hideListeningIndicator() {
        const indicator = document.getElementById('voiceListeningIndicator');
        if (indicator) {
            indicator.style.display = 'none';
        }
    }

    handleError(error) {
        let message = 'Voice recognition error occurred';
        
        switch (error) {
            case 'no-speech':
                message = 'No speech detected. Please try again.';
                break;
            case 'audio-capture':
                message = 'No microphone found. Please connect a microphone.';
                break;
            case 'not-allowed':
                message = 'Microphone permission denied. Please allow microphone access.';
                break;
            case 'network':
                message = 'Network error. Please check your connection.';
                break;
        }

        this.showError(message);
        this.stopListening();
    }

    showError(message) {
        const errorDiv = document.createElement('div');
        errorDiv.className = 'alert alert-warning alert-dismissible fade show position-fixed';
        errorDiv.style.cssText = 'top: 20px; right: 20px; z-index: 9999; min-width: 300px;';
        errorDiv.innerHTML = `
            ${message}
            <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
        `;
        document.body.appendChild(errorDiv);

        setTimeout(() => {
            errorDiv.remove();
        }, 5000);
    }

    showUnsupportedMessage() {
        const message = document.createElement('div');
        message.className = 'alert alert-info';
        message.innerHTML = `
            <strong>Voice recognition not available</strong><br>
            Your browser doesn't support voice recognition. Please use Chrome, Edge, or Safari.
        `;
        const voiceSection = document.getElementById('voiceSection');
        if (voiceSection) {
            voiceSection.appendChild(message);
        }
    }

    speak(text) {
        if ('speechSynthesis' in window) {
            const utterance = new SpeechSynthesisUtterance(text);
            utterance.lang = 'en-US';
            utterance.rate = 1.0;
            utterance.pitch = 1.0;
            
            // Use a more natural voice if available
            const voices = speechSynthesis.getVoices();
            const preferredVoice = voices.find(voice => 
                voice.lang.includes('en') && voice.name.includes('Natural')
            ) || voices.find(voice => voice.lang.includes('en-US'));
            
            if (preferredVoice) {
                utterance.voice = preferredVoice;
            }
            
            speechSynthesis.speak(utterance);
        }
    }
}

// Initialize voice recognition
document.addEventListener('DOMContentLoaded', () => {
    window.voiceRecognition = new VoiceRecognition();

    // Setup voice toggle button
    const voiceButton = document.getElementById('voiceToggleButton');
    if (voiceButton) {
        voiceButton.addEventListener('click', () => {
            if (window.voiceRecognition.isListening) {
                window.voiceRecognition.stopListening();
            } else {
                window.voiceRecognition.startListening(async (transcript) => {
                    console.log('Voice command:', transcript);
                    
                    // Send to backend
                    try {
                        const response = await fetch('/api/voice/command', {
                            method: 'POST',
                            headers: {
                                'Content-Type': 'application/json',
                            },
                            body: JSON.stringify({ transcript: transcript })
                        });
                        
                        const data = await response.json();
                        
                        if (data.success && data.response) {
                            // Display response
                            if (window.fitnessBot) {
                                window.fitnessBot.addMessage(data.response, 'bot');
                            }
                            
                            // Speak response
                            window.voiceRecognition.speak(data.response);
                        }
                    } catch (error) {
                        console.error('Error processing voice command:', error);
                    }
                });
            }
        });
    }
});
235 lines•8 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