| |
| <!DOCTYPE html> |
| <html> |
| <head> |
| <title>Video Accent Analyzer</title> |
| <script src="https://cdn.plot.ly/plotly-latest.min.js"></script> |
| <style> |
| body { |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; |
| max-width: 1000px; |
| margin: 0 auto; |
| padding: 20px; |
| background-color: #f5f5f5; |
| } |
| .container { |
| background: white; |
| padding: 20px; |
| border-radius: 10px; |
| box-shadow: 0 2px 4px rgba(0,0,0,0.1); |
| } |
| .input-group { |
| margin-bottom: 20px; |
| } |
| input, button { |
| padding: 10px; |
| margin: 5px 0; |
| border-radius: 5px; |
| border: 1px solid #ddd; |
| } |
| input[type="text"] { |
| width: 100%; |
| box-sizing: border-box; |
| } |
| button { |
| background: linear-gradient(45deg, #4CAF50, #2196F3); |
| color: white; |
| border: none; |
| cursor: pointer; |
| transition: transform 0.2s; |
| } |
| button:hover { |
| transform: scale(1.02); |
| } |
| #results { |
| margin-top: 20px; |
| padding: 20px; |
| border-radius: 5px; |
| background-color: #f8f9fa; |
| } |
| .error { |
| color: red; |
| padding: 10px; |
| background-color: #fee; |
| border-radius: 5px; |
| } |
| #plot { |
| margin-top: 20px; |
| } |
| .metric { |
| display: inline-block; |
| padding: 10px; |
| margin: 5px; |
| background: #fff; |
| border-radius: 5px; |
| box-shadow: 0 1px 3px rgba(0,0,0,0.1); |
| } |
| </style> |
| </head> |
| <body> |
| <div class="container"> |
| <h1>🎧 Video Accent Analyzer</h1> |
|
|
| <div class="input-group"> |
| <input type="text" id="videoUrl" placeholder="Enter YouTube, Loom, or direct video URL"> |
| <input type="number" id="duration" value="30" min="10" max="120" step="10"> |
| <button onclick="analyzeVideo()">Analyze Video</button> |
| </div> |
|
|
| <div id="loading" style="display: none;"> |
| Analyzing video... Please wait... |
| </div> |
|
|
| <div id="results" style="display: none;"></div> |
| <div id="plot"></div> |
| </div> |
|
|
| <script> |
| async function analyzeVideo() { |
| const url = document.getElementById('videoUrl').value; |
| const duration = document.getElementById('duration').value; |
| const loading = document.getElementById('loading'); |
| const results = document.getElementById('results'); |
| const plot = document.getElementById('plot'); |
| |
| if (!url) { |
| alert('Please enter a video URL'); |
| return; |
| } |
| |
| loading.style.display = 'block'; |
| results.style.display = 'none'; |
| plot.innerHTML = ''; |
| |
| try { |
| const response = await fetch('/api/analyze', { |
| method: 'POST', |
| headers: { |
| 'Content-Type': 'application/json', |
| }, |
| body: JSON.stringify({ url, duration }), |
| }); |
| |
| const data = await response.json(); |
| |
| if (data.error) { |
| results.innerHTML = `<div class="error">Error: ${data.error}</div>`; |
| results.style.display = 'block'; |
| return; |
| } |
| |
| |
| results.innerHTML = ` |
| <h2>Analysis Results</h2> |
| <div class="metric"> |
| <strong>Predicted Accent:</strong><br> |
| ${data.predicted_accent} |
| </div> |
| <div class="metric"> |
| <strong>Confidence:</strong><br> |
| ${data.accent_confidence.toFixed(1)}% |
| </div> |
| <div class="metric"> |
| <strong>English Confidence:</strong><br> |
| ${data.english_confidence.toFixed(1)}% |
| </div> |
| <div class="metric"> |
| <strong>Audio Duration:</strong><br> |
| ${data.audio_duration.toFixed(1)}s |
| </div> |
| `; |
| |
| |
| Plotly.newPlot('plot', data.plot.data, data.plot.layout); |
| results.style.display = 'block'; |
| |
| } catch (error) { |
| results.innerHTML = `<div class="error">Error: ${error.message}</div>`; |
| results.style.display = 'block'; |
| } finally { |
| loading.style.display = 'none'; |
| } |
| } |
| </script> |
| </body> |
| </html> |