Epona01's picture
Update app.py
07ec947 verified
#!/usr/bin/env python3
"""
Tru-Stride: AI-Powered Horse Gait Analysis
HuggingFace Space Application
This improved Gradio app provides:
- Better UI/UX for horse stride analysis
- Video processing capabilities
- Detailed analysis results
- Professional interface design
"""
import gradio as gr
import numpy as np
import cv2
import tempfile
import os
import json
from datetime import datetime
import base64
import io
from PIL import Image
# Mock analysis function (replace with your actual model)
def analyze_horse_gait(video_path):
"""
Analyze horse gait from video file
Replace this with your actual pose classification model
"""
try:
# Simulate processing time
import time
time.sleep(2)
# Mock analysis results - replace with your actual model inference
# This should call your trained pose classification model
results = {
"stride_pattern": np.random.choice(["normal", "abnormal"], p=[0.7, 0.3]),
"confidence": round(np.random.uniform(0.75, 0.95), 3),
"analysis_time": "2.3 seconds",
"details": "AI analysis completed using advanced pose estimation and gait classification",
"metrics": {
"stride_length": "Normal range (1.2-1.4m)" if np.random.random() > 0.3 else "Slightly reduced",
"gait_symmetry": "Balanced" if np.random.random() > 0.2 else "Minor asymmetry detected",
"timing": "Regular" if np.random.random() > 0.3 else "Irregular",
"energy_efficiency": round(np.random.uniform(0.7, 0.95), 2)
},
"recommendations": generate_recommendations(np.random.choice(["normal", "abnormal"], p=[0.7, 0.3]))
}
return results
except Exception as e:
return {
"error": f"Analysis failed: {str(e)}",
"stride_pattern": "error",
"confidence": 0.0,
"analysis_time": "0 seconds",
"details": "Unable to process video",
"metrics": {},
"recommendations": []
}
def generate_recommendations(stride_pattern):
"""Generate recommendations based on analysis results"""
if stride_pattern == "normal":
return [
"βœ… Gait pattern appears healthy",
"πŸ”„ Continue regular exercise routine",
"πŸ“Š Monitor for any changes over time",
"πŸ₯ Routine veterinary check recommended"
]
else:
return [
"⚠️ Irregular gait pattern detected",
"πŸ₯ Veterinary consultation recommended",
"πŸ” Consider detailed biomechanical assessment",
"πŸ“ Document any behavioral changes",
"πŸ›‘ Avoid intensive training until cleared"
]
def process_video_analysis(video_file):
"""Main function to process video and return formatted results"""
if video_file is None:
return "Please upload a video file", "", "", ""
try:
# Analyze the video
results = analyze_horse_gait(video_file)
if "error" in results:
return results["error"], "", "", ""
# Format main result
if results["stride_pattern"] == "normal":
main_result = f"βœ… **NORMAL GAIT PATTERN**\n\nConfidence: {results['confidence']*100:.1f}%"
result_color = "green"
else:
main_result = f"⚠️ **ABNORMAL GAIT PATTERN**\n\nConfidence: {results['confidence']*100:.1f}%"
result_color = "orange"
# Format detailed metrics
metrics_text = "## πŸ“Š Detailed Analysis\n\n"
for key, value in results["metrics"].items():
metrics_text += f"**{key.replace('_', ' ').title()}:** {value}\n\n"
metrics_text += f"**Analysis Time:** {results['analysis_time']}\n\n"
metrics_text += f"**Processing Details:** {results['details']}"
# Format recommendations
recommendations_text = "## πŸ’‘ Recommendations\n\n"
for rec in results["recommendations"]:
recommendations_text += f"β€’ {rec}\n\n"
# Create summary for download
summary = {
"timestamp": datetime.now().isoformat(),
"analysis_results": results,
"video_filename": os.path.basename(video_file) if video_file else "unknown"
}
return main_result, metrics_text, recommendations_text, json.dumps(summary, indent=2)
except Exception as e:
error_msg = f"❌ **ANALYSIS ERROR**\n\nError: {str(e)}"
return error_msg, "", "", ""
# Custom CSS for better styling
custom_css = """
.main-container {
max-width: 1200px;
margin: 0 auto;
}
.result-normal {
background-color: #d4edda;
border: 1px solid #c3e6cb;
border-radius: 8px;
padding: 15px;
color: #155724;
}
.result-abnormal {
background-color: #f8d7da;
border: 1px solid #f5c6cb;
border-radius: 8px;
padding: 15px;
color: #721c24;
}
.metrics-section {
background-color: #f8f9fa;
border-radius: 8px;
padding: 15px;
margin: 10px 0;
}
.recommendations-section {
background-color: #e7f3ff;
border-radius: 8px;
padding: 15px;
margin: 10px 0;
}
"""
# Create the Gradio interface
def create_interface():
with gr.Blocks(css=custom_css, title="Tru-Stride: Horse Gait Analysis") as interface:
# Header
gr.HTML("""
<div style="text-align: center; margin-bottom: 30px;">
<h1 style="color: #2c3e50; font-size: 2.5em; margin-bottom: 10px;">
🐎 Tru-Stride
</h1>
<h2 style="color: #7f8c8d; font-size: 1.2em; font-weight: normal;">
AI-Powered Horse Gait Analysis & Stride Classification
</h2>
<p style="color: #95a5a6; margin-top: 15px;">
Upload a video of your horse's movement for professional-grade gait analysis
</p>
</div>
""")
with gr.Row():
with gr.Column(scale=1):
# Video upload section
gr.HTML("<h3>πŸ“Ή Video Upload</h3>")
video_input = gr.Video(
label="Horse Movement Video",
height=400,
show_download_button=False
)
gr.HTML("""
<div style="background-color: #f8f9fa; padding: 15px; border-radius: 8px; margin: 10px 0;">
<h4>πŸ“‹ Video Guidelines:</h4>
<ul>
<li><strong>Duration:</strong> 10-60 seconds recommended</li>
<li><strong>Quality:</strong> Clear side view of horse</li>
<li><strong>Lighting:</strong> Good natural or artificial lighting</li>
<li><strong>Gait:</strong> Walk, trot, or canter</li>
<li><strong>Format:</strong> MP4, MOV, AVI supported</li>
<li><strong>Size:</strong> Maximum 100MB</li>
</ul>
</div>
""")
analyze_btn = gr.Button(
"πŸ” Analyze Gait Pattern",
variant="primary",
size="lg"
)
with gr.Column(scale=1):
# Results section
gr.HTML("<h3>πŸ“Š Analysis Results</h3>")
result_output = gr.Markdown(
label="Main Result",
value="Upload a video and click 'Analyze Gait Pattern' to begin"
)
metrics_output = gr.Markdown(
label="Detailed Metrics",
value=""
)
recommendations_output = gr.Markdown(
label="Recommendations",
value=""
)
# Analysis report download
with gr.Row():
gr.HTML("<h3>πŸ“„ Analysis Report</h3>")
with gr.Row():
report_output = gr.Textbox(
label="Detailed JSON Report (for veterinarians/professionals)",
lines=8,
max_lines=15,
value="",
show_copy_button=True
)
# Disclaimer
gr.HTML("""
<div style="background-color: #fff3cd; border: 1px solid #ffeaa7; border-radius: 8px; padding: 15px; margin: 20px 0;">
<h4 style="color: #856404;">⚠️ Important Disclaimer</h4>
<p style="color: #856404; margin: 0;">
This AI analysis tool is for informational purposes only and does not replace professional veterinary diagnosis.
Always consult with a qualified veterinarian for health concerns or before making training decisions.
</p>
</div>
""")
# Wire up the interface
analyze_btn.click(
fn=process_video_analysis,
inputs=[video_input],
outputs=[result_output, metrics_output, recommendations_output, report_output]
)
# Add example videos if available
gr.HTML("""
<div style="margin-top: 30px; text-align: center;">
<h3>🎯 About Tru-Stride</h3>
<p>
Tru-Stride uses advanced computer vision and machine learning to analyze horse movement patterns,
helping trainers, veterinarians, and horse owners assess gait quality and detect potential issues early.
</p>
</div>
""")
return interface
# Create and launch the interface
if __name__ == "__main__":
interface = create_interface()
interface.launch(
server_name="0.0.0.0",
server_port=7860,
share=False,
show_error=True
)