Spaces:
Configuration error
Configuration error
| <html lang="en" class="dark"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Elite Transcript AI 🔮</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <script src="https://unpkg.com/feather-icons"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.net.min.js"></script> | |
| <script> | |
| tailwind.config = { | |
| darkMode: 'class', | |
| theme: { | |
| extend: { | |
| colors: { | |
| primary: { | |
| 500: '#00f0ff', | |
| }, | |
| secondary: { | |
| 500: '#7b2dff', | |
| } | |
| }, | |
| fontFamily: { | |
| sans: ['Inter', 'sans-serif'], | |
| }, | |
| } | |
| } | |
| } | |
| </script> | |
| <style> | |
| #vanta-bg { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| z-index: -1; | |
| opacity: 0.15; | |
| } | |
| .glow-text { | |
| text-shadow: 0 0 8px rgba(0, 240, 255, 0.7); | |
| } | |
| .glow-box { | |
| box-shadow: 0 0 15px rgba(0, 240, 255, 0.5); | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-gray-900 text-gray-100 min-h-screen"> | |
| <div id="vanta-bg"></div> | |
| <main class="container mx-auto px-4 py-12 max-w-6xl"> | |
| <div class="text-center mb-12"> | |
| <h1 class="text-5xl md:text-6xl font-bold mb-4 glow-text"> | |
| Elite <span class="text-primary-500">Transcript</span> AI | |
| </h1> | |
| <p class="text-xl text-gray-300 max-w-2xl mx-auto"> | |
| GPU-accelerated verbatim transcription for YouTube & TikTok | |
| </p> | |
| <div class="mt-4"> | |
| <a href="/deployment.html" class="text-primary-500 hover:text-primary-400 flex items-center justify-center gap-2"> | |
| <i data-feather="cloud"></i> Deployment Instructions | |
| </a> | |
| </div> | |
| </div> | |
| <div class="grid grid-cols-1 lg:grid-cols-2 gap-8"> | |
| <!-- Input Panel --> | |
| <div class="bg-gray-800/70 backdrop-blur-sm rounded-xl p-6 glow-box border border-gray-700"> | |
| <h2 class="text-2xl font-bold mb-6 text-primary-500 flex items-center gap-2"> | |
| <i data-feather="link"></i> Video URL | |
| </h2> | |
| <div class="space-y-6"> | |
| <div class="relative"> | |
| <input | |
| type="text" | |
| id="video-url" | |
| placeholder="https://youtube.com/watch?v=..." | |
| class="w-full bg-gray-700/50 border border-gray-600 rounded-lg px-4 py-3 text-gray-100 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-transparent" | |
| > | |
| <button id="clear-btn" class="absolute right-3 top-3 text-gray-400 hover:text-gray-200"> | |
| <i data-feather="x"></i> | |
| </button> | |
| </div> | |
| <div class="flex flex-wrap gap-3"> | |
| <button id="submit-btn" class="bg-primary-500 hover:bg-primary-600 text-gray-900 font-medium px-6 py-3 rounded-lg flex items-center gap-2 transition-all"> | |
| <i data-feather="mic"></i> Transcribe | |
| </button> | |
| <button id="batch-toggle" class="border border-gray-600 hover:bg-gray-700/50 text-gray-200 px-4 py-3 rounded-lg flex items-center gap-2 transition-all"> | |
| <i data-feather="list"></i> Batch Mode | |
| </button> | |
| </div> | |
| <div id="batch-input" class="hidden"> | |
| <textarea | |
| class="w-full bg-gray-700/50 border border-gray-600 rounded-lg px-4 py-3 text-gray-100 h-32 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-transparent" | |
| placeholder="Enter multiple URLs (one per line or comma separated)" | |
| ></textarea> | |
| </div> | |
| <div class="bg-gray-700/30 rounded-lg p-4"> | |
| <div class="flex items-center gap-3 mb-3"> | |
| <i data-feather="settings" class="text-secondary-500"></i> | |
| <h3 class="font-medium">Options</h3> | |
| </div> | |
| <div class="space-y-3 text-sm"> | |
| <label class="flex items-center gap-2 cursor-pointer"> | |
| <input type="checkbox" id="auto-punctuation" class="accent-primary-500" checked> | |
| Auto Punctuation | |
| </label> | |
| <label class="flex items-center gap-2 cursor-pointer"> | |
| <input type="checkbox" id="include-timestamps" class="accent-primary-500" checked> | |
| Include Timestamps | |
| </label> | |
| <label class="flex items-center gap-2 cursor-pointer"> | |
| <input type="checkbox" id="translate" class="accent-primary-500"> | |
| Translate to English | |
| </label> | |
| </div> | |
| </div> | |
| </div> | |
| <div id="progress-container" class="mt-6 hidden"> | |
| <div class="flex justify-between mb-2 text-sm text-gray-300"> | |
| <span id="progress-status">Initializing...</span> | |
| <span id="progress-percent">0%</span> | |
| </div> | |
| <div class="w-full bg-gray-700 rounded-full h-2.5"> | |
| <div id="progress-bar" class="bg-primary-500 h-2.5 rounded-full" style="width: 0%"></div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Output Panel --> | |
| <div class="bg-gray-800/70 backdrop-blur-sm rounded-xl p-6 border border-gray-700"> | |
| <div class="flex justify-between items-center mb-6"> | |
| <h2 class="text-2xl font-bold text-primary-500 flex items-center gap-2"> | |
| <i data-feather="file-text"></i> Transcript | |
| </h2> | |
| <div id="export-buttons" class="hidden flex-wrap gap-2"> | |
| <button id="copy-btn" class="bg-gray-700 hover:bg-gray-600 text-gray-200 px-3 py-2 rounded-lg flex items-center gap-2 text-sm transition-all"> | |
| <i data-feather="copy"></i> Copy | |
| </button> | |
| <button id="export-txt" class="bg-gray-700 hover:bg-gray-600 text-gray-200 px-3 py-2 rounded-lg flex items-center gap-2 text-sm transition-all"> | |
| <i data-feather="download"></i> TXT | |
| </button> | |
| <button id="export-srt" class="bg-gray-700 hover:bg-gray-600 text-gray-200 px-3 py-2 rounded-lg flex items-center gap-2 text-sm transition-all"> | |
| <i data-feather="download"></i> SRT | |
| </button> | |
| <button id="export-docx" class="bg-gray-700 hover:bg-gray-600 text-gray-200 px-3 py-2 rounded-lg flex items-center gap-2 text-sm transition-all"> | |
| <i data-feather="download"></i> DOCX | |
| </button> | |
| </div> | |
| </div> | |
| <div id="transcript-container" class="hidden bg-gray-900 rounded-lg p-4 h-96 overflow-y-auto"> | |
| <div id="transcript-content" class="font-mono text-sm whitespace-pre-wrap"></div> | |
| </div> | |
| <div id="empty-state" class="flex flex-col items-center justify-center h-96 text-center text-gray-400"> | |
| <i data-feather="type" class="w-12 h-12 mb-4"></i> | |
| <h3 class="text-lg font-medium mb-2">Waiting for transcription</h3> | |
| <p class="max-w-xs">Enter a YouTube or TikTok URL to generate a transcript</p> | |
| </div> | |
| <div id="error-state" class="hidden flex-col items-center justify-center h-96 text-center text-red-400"> | |
| <i data-feather="alert-circle" class="w-12 h-12 mb-4"></i> | |
| <h3 class="text-lg font-medium mb-2" id="error-title">Error Occurred</h3> | |
| <p class="max-w-xs" id="error-message"></p> | |
| <button id="retry-btn" class="mt-4 bg-gray-700 hover:bg-gray-600 text-gray-200 px-4 py-2 rounded-lg flex items-center gap-2 transition-all"> | |
| <i data-feather="refresh-cw"></i> Try Again | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </main> | |
| <script> | |
| // Initialize Vanta.js background | |
| VANTA.NET({ | |
| el: "#vanta-bg", | |
| mouseControls: true, | |
| touchControls: true, | |
| gyroControls: false, | |
| minHeight: 200.00, | |
| minWidth: 200.00, | |
| scale: 1.00, | |
| scaleMobile: 1.00, | |
| color: 0x3b82f6, | |
| backgroundColor: 0x111827, | |
| points: 10.00, | |
| maxDistance: 20.00, | |
| spacing: 15.00 | |
| }); | |
| // Initialize Feather Icons | |
| feather.replace(); | |
| // DOM Elements | |
| const videoUrlInput = document.getElementById('video-url'); | |
| const clearBtn = document.getElementById('clear-btn'); | |
| const submitBtn = document.getElementById('submit-btn'); | |
| const batchToggle = document.getElementById('batch-toggle'); | |
| const batchInput = document.getElementById('batch-input'); | |
| const progressContainer = document.getElementById('progress-container'); | |
| const progressBar = document.getElementById('progress-bar'); | |
| const progressStatus = document.getElementById('progress-status'); | |
| const progressPercent = document.getElementById('progress-percent'); | |
| const transciptContainer = document.getElementById('transcript-container'); | |
| const transciptContent = document.getElementById('transcript-content'); | |
| const emptyState = document.getElementById('empty-state'); | |
| const errorState = document.getElementById('error-state'); | |
| const exportButtons = document.getElementById('export-buttons'); | |
| // Event Listeners | |
| clearBtn.addEventListener('click', () => { | |
| videoUrlInput.value = ''; | |
| }); | |
| batchToggle.addEventListener('click', () => { | |
| batchInput.classList.toggle('hidden'); | |
| if (batchInput.classList.contains('hidden')) { | |
| batchToggle.innerHTML = '<i data-feather="list"></i> Batch Mode'; | |
| } else { | |
| batchToggle.innerHTML = '<i data-feather="x"></i> Close Batch'; | |
| } | |
| feather.replace(); | |
| }); | |
| submitBtn.addEventListener('click', async () => { | |
| const url = videoUrlInput.value.trim(); | |
| if (!url) return; | |
| // Show progress | |
| emptyState.classList.add('hidden'); | |
| errorState.classList.add('hidden'); | |
| progressContainer.classList.remove('hidden'); | |
| updateProgress('Validating URL', 10); | |
| try { | |
| // Validate URL | |
| if (!isValidUrl(url)) { | |
| throw new Error('Please enter a valid YouTube or TikTok URL'); | |
| } | |
| updateProgress('Downloading audio', 30); | |
| // Simulate processing (replace with actual API call) | |
| await new Promise(resolve => setTimeout(resolve, 1500)); | |
| updateProgress('Transcribing audio', 60); | |
| // Simulate transcription | |
| await new Promise(resolve => setTimeout(resolve, 3000)); | |
| updateProgress('Finalizing transcript', 90); | |
| // Simulate final processing | |
| await new Promise(resolve => setTimeout(resolve, 500)); | |
| // Show results | |
| transciptContainer.classList.remove('hidden'); | |
| exportButtons.classList.remove('hidden'); | |
| progressContainer.classList.add('hidden'); | |
| // Demo transcript | |
| const demoTranscript = `[00:00:00] Welcome to the Elite Transcript AI demo. | |
| [00:00:05] This is a simulated transcript to demonstrate the output format. | |
| [00:00:10] The actual application would connect to a powerful backend using Whisper-v3 AI. | |
| [00:00:15] Timestamps are inserted automatically every few seconds. | |
| [00:00:20] The system handles ums, ahs, and other speech disfluencies. | |
| [00:00:25] Support for multiple export formats including TXT, SRT, and DOCX.`; | |
| transciptContent.textContent = demoTranscript; | |
| } catch (error) { | |
| showError(error.message); | |
| } | |
| }); | |
| // Helper functions | |
| function isValidUrl(url) { | |
| try { | |
| const parsed = new URL(url); | |
| return parsed.hostname.includes('youtube.com') || | |
| parsed.hostname.includes('youtu.be') || | |
| parsed.hostname.includes('tiktok.com'); | |
| } catch { | |
| return false; | |
| } | |
| } | |
| function updateProgress(status, percent) { | |
| progressStatus.textContent = status; | |
| progressPercent.textContent = `${percent}%`; | |
| progressBar.style.width = `${percent}%`; | |
| } | |
| function showError(message) { | |
| progressContainer.classList.add('hidden'); | |
| errorState.classList.remove('hidden'); | |
| document.getElementById('error-message').textContent = message; | |
| feather.replace(); | |
| } | |
| // Export button handlers | |
| document.getElementById('copy-btn').addEventListener('click', () => { | |
| navigator.clipboard.writeText(transciptContent.textContent); | |
| alert('Transcript copied to clipboard!'); | |
| }); | |
| document.getElementById('export-txt').addEventListener('click', () => { | |
| alert('Exporting as TXT file...'); | |
| }); | |
| document.getElementById('export-srt').addEventListener('click', () => { | |
| alert('Exporting as SRT file...'); | |
| }); | |
| document.getElementById('export-docx').addEventListener('click', () => { | |
| alert('Exporting as DOCX file...'); | |
| }); | |
| document.getElementById('retry-btn').addEventListener('click', () => { | |
| errorState.classList.add('hidden'); | |
| emptyState.classList.remove('hidden'); | |
| }); | |
| </script> | |
| </body> | |
| </html> |