Spaces:
Running
on
T4
Running
on
T4
File size: 9,328 Bytes
f20fe1f |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bodybuilding Pose Analyzer</title>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/tailwind.min.css" rel="stylesheet">
</head>
<body class="bg-gray-100 min-h-screen">
<div class="container mx-auto px-4 py-8">
<h1 class="text-4xl font-bold text-center mb-8">Bodybuilding Pose Analyzer</h1>
<div class="max-w-2xl mx-auto bg-white rounded-lg shadow-lg p-6">
<div class="mb-6">
<h2 class="text-2xl font-semibold mb-4">Upload Video</h2>
<form id="uploadForm" class="space-y-4">
<div class="border-2 border-dashed border-gray-300 rounded-lg p-6 text-center">
<input type="file" id="videoInput" accept="video/*" class="hidden">
<label for="videoInput" class="cursor-pointer">
<div class="text-gray-600">
<svg class="mx-auto h-12 w-12" stroke="currentColor" fill="none" viewBox="0 0 48 48">
<path d="M28 8H12a4 4 0 00-4 4v20m32-12v8m0 0v8a4 4 0 01-4 4H12a4 4 0 01-4-4v-4m32-4l-3.172-3.172a4 4 0 00-5.656 0L28 28M8 32l9.172-9.172a4 4 0 015.656 0L28 28m0 0l4 4m4-24h8m-4-4v8m-12 4h.02" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
</svg>
<p class="mt-1">Click to upload a video</p>
<p id="fileName" class="text-sm text-gray-500 mt-1"></p>
</div>
</label>
</div>
<div>
<label class="block text-sm font-medium text-gray-700">Choose Model:</label>
<div class="mt-1 flex rounded-md shadow-sm">
<div class="relative flex items-stretch flex-grow focus-within:z-10">
<label class="inline-flex items-center">
<input type="radio" class="form-radio" name="model_choice" value="movenet" checked>
<span class="ml-2">Gladiator BB</span>
</label>
<label class="inline-flex items-center ml-6">
<input type="radio" class="form-radio" name="model_choice" value="Gladiator SupaDot">
<span class="ml-2">Gladiator SupaDot</span>
</label>
</div>
</div>
</div>
<div id="gladiatorBBOptions" class="space-y-4">
<div>
<label class="block text-sm font-medium text-gray-700">Gladiator BB Variant:</label>
<div class="mt-1 flex rounded-md shadow-sm">
<div class="relative flex items-stretch flex-grow focus-within:z-10">
<label class="inline-flex items-center">
<input type="radio" class="form-radio" name="movenet_variant" value="lightning" checked>
<span class="ml-2">Lightning (Faster, Less Accurate)</span>
</label>
<label class="inline-flex items-center ml-6">
<input type="radio" class="form-radio" name="movenet_variant" value="thunder">
<span class="ml-2">Thunder (Slower, More Accurate)</span>
</label>
</div>
</div>
</div>
</div>
<button type="submit" class="w-full bg-blue-500 text-white py-2 px-4 rounded-lg hover:bg-blue-600 transition duration-200">
Process Video
</button>
</form>
</div>
<div id="result" class="hidden">
<h2 class="text-2xl font-semibold mb-4">Results</h2>
<div class="aspect-w-16 aspect-h-9">
<video id="outputVideo" controls class="w-full rounded-lg"></video>
</div>
</div>
<div id="loading" class="hidden">
<div class="flex items-center justify-center">
<div class="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-500"></div>
</div>
<p class="text-center mt-4">Processing video...</p>
</div>
</div>
</div>
<script>
document.getElementById('videoInput').addEventListener('change', function() {
const fileName = this.files[0] ? this.files[0].name : 'No file selected';
document.getElementById('fileName').textContent = fileName;
});
document.querySelectorAll('input[name="model_choice"]').forEach(radio => {
radio.addEventListener('change', function() {
const gladiatorBBOptions = document.getElementById('gladiatorBBOptions');
if (this.value === 'movenet') {
gladiatorBBOptions.classList.remove('hidden');
} else {
gladiatorBBOptions.classList.add('hidden');
}
});
});
// Trigger change event on page load for the initially checked model_choice
document.querySelector('input[name="model_choice"]:checked').dispatchEvent(new Event('change'));
document.getElementById('uploadForm').addEventListener('submit', async (e) => {
e.preventDefault();
const fileInput = document.getElementById('videoInput');
const file = fileInput.files[0];
if (!file) {
alert('Please select a video file');
return;
}
const formData = new FormData();
formData.append('video', file);
const modelChoice = document.querySelector('input[name="model_choice"]:checked').value;
formData.append('model_choice', modelChoice);
if (modelChoice === 'movenet') {
const movenetVariant = document.querySelector('input[name="movenet_variant"]:checked').value;
formData.append('movenet_variant', movenetVariant);
}
// Show loading
document.getElementById('loading').classList.remove('hidden');
document.getElementById('result').classList.add('hidden');
try {
const response = await fetch('/upload', {
method: 'POST',
body: formData
});
console.log('[CLIENT] Full response object from /upload:', response);
console.log('[CLIENT] Response status from /upload:', response.status);
console.log('[CLIENT] Response status text from /upload:', response.statusText);
const data = await response.json();
console.log('[CLIENT] Parsed JSON data from /upload:', data);
if (response.ok) {
console.log('[CLIENT] Response from /upload is OK (status 200-299)');
const videoElement = document.getElementById('outputVideo');
const resultDiv = document.getElementById('result');
console.log('[CLIENT] Setting video src to:', data.output_path);
videoElement.src = data.output_path;
resultDiv.classList.remove('hidden');
videoElement.load();
console.log('[CLIENT] Called video.load()');
videoElement.onloadeddata = () => {
console.log('[CLIENT] Video data loaded successfully.');
};
videoElement.onerror = (e) => {
console.error('[CLIENT] Video player error:', e);
console.error('[CLIENT] Video src that failed:', videoElement.src);
alert('Error loading video. Check browser console for details.');
};
} else {
console.error('[CLIENT] Response from /upload not OK. Status:', response.status);
alert(data.error || `Server error: ${response.status} ${response.statusText}. Check browser console.`);
}
} catch (error) {
console.error('[CLIENT] Fetch Error during /upload:', error);
alert('A critical error occurred while uploading/processing the video. Check browser console.');
} finally {
document.getElementById('loading').classList.add('hidden');
}
});
</script>
</body>
</html> |