Spaces:
Sleeping
Sleeping
#!/usr/bin/env python3 | |
""" | |
GATE Motion Analysis - Gradio Deployment Version | |
Optimised for HuggingFace Spaces deployment with minimal dependencies | |
""" | |
import os | |
import sys | |
import gradio as gr | |
import numpy as np | |
import cv2 | |
from pathlib import Path | |
import tempfile | |
import time | |
from datetime import datetime | |
# Simple configuration | |
DEBUG_MODE = os.getenv("DEBUG_MODE", "false").lower() == "true" | |
USE_GPU = os.getenv("USE_GPU", "false").lower() == "true" | |
class SimpleMotionAnalyzer: | |
"""Simplified motion analyzer for demo purposes.""" | |
def __init__(self): | |
self.initialized = False | |
self.init_time = datetime.now() | |
def analyze_frame(self, frame): | |
"""Simple frame analysis that works without complex dependencies.""" | |
if frame is None: | |
return None, "No frame provided", 0.0, "Please upload an image or use webcam" | |
try: | |
# Simple motion analysis placeholder | |
height, width = frame.shape[:2] if len(frame.shape) > 1 else (480, 640) | |
# Mock analysis results | |
confidence = np.random.uniform(70, 95) | |
status = f"Analysis complete - Frame size: {width}x{height}" | |
feedback = self._generate_feedback(confidence) | |
# Add simple visual overlay | |
if len(frame.shape) == 3: | |
overlay_frame = frame.copy() | |
cv2.putText(overlay_frame, f"Confidence: {confidence:.1f}%", | |
(10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2) | |
return overlay_frame, status, confidence, feedback | |
return frame, status, confidence, feedback | |
except Exception as e: | |
return frame, f"Analysis error: {str(e)}", 0.0, "Error during analysis" | |
def _generate_feedback(self, confidence): | |
"""Generate feedback based on confidence score.""" | |
if confidence > 85: | |
return "Excellent form! Keep up the good work." | |
elif confidence > 70: | |
return "Good form with room for improvement. Focus on posture." | |
else: | |
return "Form needs work. Consider slowing down and focusing on technique." | |
# Global analyzer instance | |
analyzer = SimpleMotionAnalyzer() | |
def process_image(image, exercise_type): | |
"""Process uploaded image for motion analysis.""" | |
if image is None: | |
return None, "No image provided", 0.0, "Please upload an image" | |
try: | |
# Convert PIL to numpy if needed | |
if hasattr(image, 'convert'): | |
image = np.array(image.convert('RGB')) | |
# Analyze the frame | |
result_frame, status, confidence, feedback = analyzer.analyze_frame(image) | |
return result_frame, status, confidence, f"Exercise: {exercise_type}\n{feedback}" | |
except Exception as e: | |
error_msg = f"Processing error: {str(e)}" | |
return image, error_msg, 0.0, error_msg | |
def process_video(video_path, exercise_type): | |
"""Process uploaded video for motion analysis.""" | |
if video_path is None: | |
return None, "No video provided", 0.0, "Please upload a video" | |
try: | |
# Read video and process first frame as demo | |
cap = cv2.VideoCapture(video_path) | |
ret, frame = cap.read() | |
cap.release() | |
if not ret: | |
return None, "Could not read video", 0.0, "Video format not supported" | |
# Convert BGR to RGB | |
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) | |
# Analyze the frame | |
result_frame, status, confidence, feedback = analyzer.analyze_frame(frame_rgb) | |
return result_frame, status, confidence, f"Exercise: {exercise_type}\n{feedback} (First frame analysis)" | |
except Exception as e: | |
error_msg = f"Video processing error: {str(e)}" | |
return None, error_msg, 0.0, error_msg | |
def get_system_info(): | |
"""Get system information for debugging.""" | |
info = { | |
"Python Version": sys.version, | |
"OpenCV Available": True, | |
"GPU Available": USE_GPU, | |
"Debug Mode": DEBUG_MODE, | |
"Analyzer Initialized": analyzer.initialized, | |
"Server Time": datetime.now().strftime("%Y-%m-%d %H:%M:%S") | |
} | |
info_text = "\n".join([f"**{k}:** {v}" for k, v in info.items()]) | |
return info_text | |
def create_interface(): | |
"""Create the main Gradio interface.""" | |
# Define custom CSS to fix styling issues | |
custom_css = """ | |
.gradio-container { | |
max-width: 1200px !important; | |
margin: auto; | |
} | |
.main-header { | |
text-align: center; | |
color: #2563eb; | |
margin-bottom: 2rem; | |
} | |
.status-box { | |
background: #f8fafc; | |
border: 1px solid #e2e8f0; | |
border-radius: 8px; | |
padding: 1rem; | |
margin: 0.5rem 0; | |
} | |
.metric-display { | |
font-size: 1.2rem; | |
font-weight: bold; | |
color: #059669; | |
} | |
""" | |
with gr.Blocks( | |
title="GATE Motion Analysis", | |
css=custom_css, | |
theme=gr.themes.Soft(), | |
analytics_enabled=False # Disable analytics to prevent tracking errors | |
) as interface: | |
gr.HTML('<h1 class="main-header">πββοΈ GATE Motion Analysis System</h1>') | |
gr.Markdown(""" | |
Welcome to the GATE Motion Analysis System! Upload an image or video to analyze exercise form. | |
**Features:** | |
- Real-time pose detection | |
- Exercise form analysis | |
- Personalized feedback | |
- Multi-exercise support | |
""") | |
with gr.Row(): | |
with gr.Column(scale=2): | |
with gr.Tabs() as tabs: | |
with gr.TabItem("πΈ Image Analysis"): | |
image_input = gr.Image( | |
label="Upload Exercise Image", | |
type="pil", | |
height=400 | |
) | |
image_exercise = gr.Dropdown( | |
choices=["Squats", "Push-ups", "Lunges", "Bicep Curls", "Deadlifts"], | |
value="Squats", | |
label="Exercise Type" | |
) | |
image_btn = gr.Button("Analyze Image", variant="primary") | |
with gr.TabItem("π₯ Video Analysis"): | |
video_input = gr.Video( | |
label="Upload Exercise Video", | |
height=400 | |
) | |
video_exercise = gr.Dropdown( | |
choices=["Squats", "Push-ups", "Lunges", "Bicep Curls", "Deadlifts"], | |
value="Squats", | |
label="Exercise Type" | |
) | |
video_btn = gr.Button("Analyze Video", variant="primary") | |
with gr.Column(scale=2): | |
gr.Markdown("### π Analysis Results") | |
result_image = gr.Image( | |
label="Analyzed Frame", | |
height=400 | |
) | |
with gr.Row(): | |
status_display = gr.Textbox( | |
label="Status", | |
value="Ready for analysis", | |
interactive=False, | |
elem_classes=["status-box"] | |
) | |
confidence_display = gr.Number( | |
label="Form Score (%)", | |
value=0, | |
interactive=False, | |
elem_classes=["metric-display"] | |
) | |
feedback_display = gr.Textbox( | |
label="Feedback & Recommendations", | |
value="Upload an image or video to get started", | |
lines=4, | |
interactive=False | |
) | |
# System information (collapsible) | |
with gr.Accordion("π§ System Information", open=False): | |
system_info = gr.Markdown(get_system_info()) | |
refresh_info_btn = gr.Button("Refresh System Info") | |
# Event handlers | |
image_btn.click( | |
fn=process_image, | |
inputs=[image_input, image_exercise], | |
outputs=[result_image, status_display, confidence_display, feedback_display] | |
) | |
video_btn.click( | |
fn=process_video, | |
inputs=[video_input, video_exercise], | |
outputs=[result_image, status_display, confidence_display, feedback_display] | |
) | |
refresh_info_btn.click( | |
fn=get_system_info, | |
outputs=[system_info] | |
) | |
# Remove automatic processing to prevent API conflicts | |
# Users must click the analyze button to process files | |
# Add footer | |
gr.Markdown(""" | |
--- | |
**GATE Motion Analysis System** - Developed for real-time exercise form analysis and feedback. | |
*Note: This is a demonstration version. For full functionality, additional models and dependencies may be required.* | |
""") | |
return interface | |
def main(): | |
"""Main function to launch the application.""" | |
print("π Starting GATE Motion Analysis System...") | |
print(f"Debug Mode: {DEBUG_MODE}") | |
print(f"GPU Support: {USE_GPU}") | |
# Create the interface | |
interface = create_interface() | |
# Conservative launch configuration with only basic parameters | |
launch_config = { | |
# "server_name": "0.0.0.0", | |
"server_port": int(os.getenv("PORT", 7860)), | |
"share": True, | |
"show_error": True, | |
"show_api": False, | |
"quiet": not DEBUG_MODE | |
} | |
try: | |
interface.launch(**launch_config) | |
except Exception as e: | |
print(f"Launch failed: {e}") | |
print("Trying minimal fallback configuration...") | |
# Ultra-minimal fallback configuration | |
interface.launch( | |
share=False, | |
show_error=True | |
) | |
if __name__ == "__main__": | |
main() |