A minimal backend service that analyzes boxing jabs from 2-second video clips and returns structured JSON feedback with cue points for interactive playback.
- Fast Processing: End-to-end response in under 3 seconds
- Low Cost: Uses Gemini Flash-Lite for efficient analysis
- Cue Points: Returns timestamps for interactive video playback
- Structured Output: Predictable JSON schema for easy client integration
- Fallback Safety: Graceful error handling with meaningful feedback
# Clone and navigate to project
cd jab-feedback-server
# Create virtual environment
python3 -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install dependencies
pip install -r requirements.txt# Copy example environment file
cp env_example.txt .env
# Edit .env and add your Gemini API key
# Get your key from: https://makersuite.google.com/app/apikey# Start the server
uvicorn main:app --reload
# Server will be available at http://localhost:8000Analyze a jab from a 2-second video clip.
Request:
- Method:
POST - Content-Type:
multipart/form-data - Body: Video file (.mp4 or .mov)
- Max file size: 50MB
- Max duration: 2.5 seconds (with tolerance)
Response:
{
"jab": {
"stance": "orthodox|southpaw|unknown",
"quality": "clean|loose|off-balance",
"confidence": 0.92,
"feedback": "Strong jab, extend fully and snap back."
},
"cue_points": [0.1, 0.4, 0.8, 1.2, 1.5, 1.8]
}Error Response:
{
"detail": "Error message describing the issue"
}The server extracts 6 frames at fixed timestamps:
0.1s: Beginning of jab motion0.4s: Arm extension phase0.8s: Peak extension1.2s: Recovery phase1.5s: Return to guard1.8s: Final position
Frames are resized to 512px width for optimal Gemini processing.
// Example of using cue points for interactive playback
const video = document.getElementById('video');
const cues = [0.1, 0.4, 0.8, 1.2, 1.5, 1.8];
let currentCueIndex = 0;
video.addEventListener('timeupdate', () => {
if (currentCueIndex < cues.length) {
const targetTime = cues[currentCueIndex];
if (Math.abs(video.currentTime - targetTime) < 0.03) {
video.pause();
showFeedback(currentCueIndex);
currentCueIndex++;
}
}
});
function showFeedback(cueIndex) {
// Display feedback overlay at this cue point
console.log(`Showing feedback for cue ${cueIndex}`);
}curl -X POST "http://localhost:8000/analyze-jab" \
-H "accept: application/json" \
-H "Content-Type: multipart/form-data" \
-F "file=@your_jab_video.mp4"- FastAPI: Modern web framework for building APIs
- OpenCV: Video processing and frame extraction
- Google GenAI: Latest Gemini API client for jab analysis
- Uvicorn: ASGI server for running the application
- Frame extraction: < 0.5s (using temporary file processing)
- Gemini API call: 1-2s
- Total response time: ~2-3s
- 6 images per request → ~6-8k tokens
- Gemini 2.0 Flash cost: ~$0.002-0.004 per clip
jab-feedback-server/
├── main.py # FastAPI application
├── requirements.txt # Python dependencies
├── env_example.txt # Environment variables template
├── README.md # This file
└── .env # Your API keys (not in git)
- API Testing: Use the interactive docs at
http://localhost:8000/docs - Video Testing: Use 2-second .mp4 files of boxing jabs
- Error Testing: Try invalid file types, oversized files, or corrupted videos
- Additional strikes (cross, hook, kicks)
- Server-side video rendering with overlays
- Progress tracking and session history
- Multi-strike analysis per clip
- Real-time video streaming analysis
uvicorn main:app --reload --host 0.0.0.0 --port 8000- Set up proper CORS configuration
- Use environment variables for API keys
- Implement request rate limiting
- Add logging and monitoring
- Consider Docker containerization
- "Could not open video file": Ensure video is valid .mp4 or .mov
- "Video too long": Video must be ≤ 2 seconds
- "File too large": Maximum file size is 50MB
- Gemini API errors: Check your API key and quota
# Run with debug logging
uvicorn main:app --reload --log-level debugMIT License - feel free to use this for your projects!