Team Ai
Apppublic

Escapingmatrixtoday/transcriptvortex-pro

sourceHugging Faceupdated 1y agoView on Hugging Face
0likes
index.html558 linesDownload Raw Back to root
1<!DOCTYPE html>2<html lang="en">3<head>4    <meta charset="UTF-8">5    <meta name="viewport" content="width=device-width, initial-scale=1.0">6    <title>TranscribeVibe Pro - Video Transcript Generator</title>7    <link rel="icon" type="image/x-icon" href="/static/favicon.ico">8    <script src="https://cdn.tailwindcss.com"></script>9    <script src="https://unpkg.com/feather-icons"></script>10    <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>11    <script src="https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.globe.min.js"></script>12    <script src="https://cdn.jsdelivr.net/npm/animejs@3.2.1/lib/anime.min.js"></script>13    <script>14        tailwind.config = {15            theme: {16                extend: {17                    colors: {18                        primary: '#6366f1',19                        secondary: '#8b5cf6',20                        dark: '#1e293b'21                    }22                }23            }24        }25    </script>26    <style>27        .vanta-container {28            position: absolute;29            top: 0;30            left: 0;31            width: 100%;32            height: 100%;33            z-index: -1;34        }35        .blur-effect {36            backdrop-filter: blur(8px);37            background-color: rgba(255, 255, 255, 0.1);38        }39        .dark .blur-effect {40            background-color: rgba(30, 41, 59, 0.7);41        }42    </style>43</head>44<body class="bg-gray-50 dark:bg-dark min-h-screen font-sans">45    <div id="vanta-bg" class="vanta-container"></div>46    47    <div class="container mx-auto px-4 py-12">48        <!-- Header -->49        <header class="mb-12 text-center">50            <h1 class="text-4xl md:text-5xl font-bold text-primary dark:text-white mb-4">51                <span class="inline-block transform hover:scale-105 transition-transform">TranscribeVibe Pro</span>52            </h1>53            <p class="text-xl text-gray-600 dark:text-gray-300 max-w-2xl mx-auto">54                Generate perfect transcripts from TikTok & YouTube videos instantly55            </p>56        </header>57 58        <!-- Main Card -->59        <div class="max-w-4xl mx-auto bg-white dark:bg-gray-800 rounded-xl shadow-2xl overflow-hidden transition-all duration-300 hover:shadow-primary/30">60            <!-- Tabs -->61            <div class="flex border-b border-gray-200 dark:border-gray-700">62                <button id="youtube-tab" class="flex-1 py-4 px-6 text-center font-medium text-gray-500 dark:text-gray-400 hover:text-primary dark:hover:text-primary border-b-2 border-transparent hover:border-primary transition-all active-tab">63                    <i data-feather="youtube" class="inline mr-2"></i> YouTube64                </button>65                <button id="tiktok-tab" class="flex-1 py-4 px-6 text-center font-medium text-gray-500 dark:text-gray-400 hover:text-primary dark:hover:text-primary border-b-2 border-transparent hover:border-primary transition-all">66                    <i data-feather="video" class="inline mr-2"></i> TikTok67                </button>68            </div>69 70            <!-- Content Area -->71            <div class="p-6 md:p-8">72                <!-- URL Input -->73                <div class="mb-8">74                    <label for="video-url" class="block text-lg font-medium text-gray-700 dark:text-gray-300 mb-3">75                        Paste your video URL here76                    </label>77                    <div class="flex flex-col md:flex-row gap-3">78                        <input 79                            type="text" 80                            id="video-url" 81                            placeholder="https://www.youtube.com/watch?v=..." 82                            class="flex-1 px-5 py-3 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-primary focus:border-primary outline-none transition-all dark:bg-gray-700 dark:text-white"83                        >84                        <button id="generate-btn" class="px-6 py-3 bg-primary hover:bg-primary-600 text-white font-medium rounded-lg transition-all flex items-center justify-center gap-2">85                            <i data-feather="play" class="w-5 h-5"></i> Generate Transcript86                        </button>87                    </div>88                </div>89 90                <!-- Status Indicator -->91                <div id="status-container" class="hidden mb-8">92                    <div class="flex items-center gap-3">93                        <div id="status-spinner" class="animate-spin">94                            <i data-feather="loader" class="w-6 h-6 text-primary"></i>95                        </div>96                        <p id="status-text" class="text-gray-700 dark:text-gray-300">Processing your video...</p>97                    </div>98                </div>99                <!-- Results -->100                <div id="results-container" class="hidden">101                    <div class="flex flex-col md:flex-row gap-6 mb-6">102                        <div class="flex-1">103                            <h3 class="text-xl font-semibold text-gray-800 dark:text-white mb-4">Full Transcript</h3>104                            <div class="bg-gray-50 dark:bg-gray-700 rounded-lg p-6 h-96 overflow-y-auto">105                                <div id="transcript-content" class="prose dark:prose-invert max-w-none text-gray-700 dark:text-gray-300">106                                    <!-- Transcript will be inserted here -->107                                </div>108                            </div>109                        </div>110                        <div class="md:w-80">111                            <h3 class="text-xl font-semibold text-gray-800 dark:text-white mb-4">Video Info</h3>112                            <div class="bg-gray-50 dark:bg-gray-700 rounded-lg p-6">113                                <div id="video-info" class="space-y-4">114                                    <div>115                                        <p class="text-sm text-gray-500 dark:text-gray-400">Title:</p>116                                        <p id="video-title" class="font-medium">-</p>117                                    </div>118                                    <div>119                                        <p class="text-sm text-gray-500 dark:text-gray-400">Duration:</p>120                                        <p id="video-duration" class="font-medium">-</p>121                                    </div>122                                    <div>123                                        <p class="text-sm text-gray-500 dark:text-gray-400">Word Count:</p>124                                        <p id="word-count" class="font-medium">-</p>125                                    </div>126                                    <div class="pt-4 border-t border-gray-200 dark:border-gray-600">127                                        <p class="text-sm text-gray-500 dark:text-gray-400">Processing Time:</p>128                                        <p id="processing-time" class="font-medium">-</p>129                                    </div>130                                </div>131                            </div>132                        </div>133                    </div>134<div class="flex justify-between items-center mb-4">135                        <h3 class="text-xl font-semibold text-gray-800 dark:text-white">Transcript</h3>136                        <div class="flex gap-2">137                            <button id="copy-btn" class="px-4 py-2 bg-gray-200 hover:bg-gray-300 dark:bg-gray-700 dark:hover:bg-gray-600 text-gray-800 dark:text-white rounded-lg transition-all flex items-center gap-2">138                                <i data-feather="copy" class="w-4 h-4"></i> Copy139                            </button>140                            <button id="download-btn" class="px-4 py-2 bg-secondary hover:bg-secondary-600 text-white rounded-lg transition-all flex items-center gap-2">141                                <i data-feather="download" class="w-4 h-4"></i> Download142                            </button>143                        </div>144                    </div>145                    <div class="bg-gray-50 dark:bg-gray-700 rounded-lg p-6">146                        <div id="transcript-content" class="prose dark:prose-invert max-w-none text-gray-700 dark:text-gray-300">147                            <!-- Transcript will be inserted here -->148                        </div>149                    </div>150                </div>151 152                <!-- Empty State -->153                <div id="empty-state" class="text-center py-12">154                    <div class="inline-block p-5 bg-gray-100 dark:bg-gray-700 rounded-full mb-5">155                        <i data-feather="file-text" class="w-10 h-10 text-gray-400 dark:text-gray-300"></i>156                    </div>157                    <h3 class="text-xl font-medium text-gray-600 dark:text-gray-300 mb-2">No Transcript Yet</h3>158                    <p class="text-gray-500 dark:text-gray-400">Paste a YouTube or TikTok URL above to generate a transcript</p>159                </div>160            </div>161        </div>162        <!-- How It Works Section -->163        <div class="max-w-4xl mx-auto mt-20 mb-16">164            <h2 class="text-3xl font-bold text-center text-primary dark:text-white mb-12">How It Works</h2>165            <div class="space-y-8">166                <div class="flex flex-col md:flex-row gap-6 items-center">167                    <div class="w-16 h-16 bg-primary-100 dark:bg-primary-900 rounded-full flex items-center justify-center shrink-0">168                        <span class="text-2xl font-bold text-primary">1</span>169                    </div>170                    <div>171                        <h3 class="text-xl font-semibold text-gray-800 dark:text-white mb-2">Paste Video URL</h3>172                        <p class="text-gray-600 dark:text-gray-400">Copy any YouTube or TikTok video URL and paste it into the input field above.</p>173                    </div>174                </div>175                <div class="flex flex-col md:flex-row gap-6 items-center">176                    <div class="w-16 h-16 bg-primary-100 dark:bg-primary-900 rounded-full flex items-center justify-center shrink-0">177                        <span class="text-2xl font-bold text-primary">2</span>178                    </div>179                    <div>180                        <h3 class="text-xl font-semibold text-gray-800 dark:text-white mb-2">AI Processing</h3>181                        <p class="text-gray-600 dark:text-gray-400">Our advanced AI analyzes the video's audio to extract every spoken word with timestamps.</p>182                    </div>183                </div>184                <div class="flex flex-col md:flex-row gap-6 items-center">185                    <div class="w-16 h-16 bg-primary-100 dark:bg-primary-900 rounded-full flex items-center justify-center shrink-0">186                        <span class="text-2xl font-bold text-primary">3</span>187                    </div>188                    <div>189                        <h3 class="text-xl font-semibold text-gray-800 dark:text-white mb-2">Get Full Transcript</h3>190                        <p class="text-gray-600 dark:text-gray-400">Receive a complete, word-for-word transcript with precise timestamps for every utterance.</p>191                    </div>192                </div>193            </div>194        </div>195 196        <!-- Features Section -->197<div class="max-w-6xl mx-auto mt-16 grid grid-cols-1 md:grid-cols-3 gap-8">198            <div class="bg-white dark:bg-gray-800 p-6 rounded-xl shadow-lg hover:shadow-primary/20 transition-all">199                <div class="w-12 h-12 bg-primary-100 dark:bg-primary-900 rounded-lg flex items-center justify-center mb-4">200                    <i data-feather="zap" class="w-6 h-6 text-primary"></i>201                </div>202                <h3 class="text-xl font-semibold text-gray-800 dark:text-white mb-2">Lightning Fast</h3>203                <p class="text-gray-600 dark:text-gray-400">Get transcripts in seconds with our powerful processing engine.</p>204            </div>205            <div class="bg-white dark:bg-gray-800 p-6 rounded-xl shadow-lg hover:shadow-primary/20 transition-all">206                <div class="w-12 h-12 bg-primary-100 dark:bg-primary-900 rounded-lg flex items-center justify-center mb-4">207                    <i data-feather="check-circle" class="w-6 h-6 text-primary"></i>208                </div>209                <h3 class="text-xl font-semibold text-gray-800 dark:text-white mb-2">Highly Accurate</h3>210                <p class="text-gray-600 dark:text-gray-400">State-of-the-art speech recognition for perfect transcripts.</p>211            </div>212            <div class="bg-white dark:bg-gray-800 p-6 rounded-xl shadow-lg hover:shadow-primary/20 transition-all">213                <div class="w-12 h-12 bg-primary-100 dark:bg-primary-900 rounded-lg flex items-center justify-center mb-4">214                    <i data-feather="lock" class="w-6 h-6 text-primary"></i>215                </div>216                <h3 class="text-xl font-semibold text-gray-800 dark:text-white mb-2">Private & Secure</h3>217                <p class="text-gray-600 dark:text-gray-400">Your data is processed securely and never stored.</p>218            </div>219        </div>220 221        <!-- Footer -->222        <footer class="mt-20 text-center text-gray-500 dark:text-gray-400">223            <p>© 2023 TranscribeVibe Pro. All rights reserved.</p>224        </footer>225    </div>226 227    <script>228        // Initialize Vanta.js background with error handling229        try {230            VANTA.GLOBE({231                el: "#vanta-bg",232                mouseControls: true,233                touchControls: true,234                gyroControls: false,235                minHeight: 200.00,236                minWidth: 200.00,237                scale: 1.00,238                scaleMobile: 1.00,239                color: 0x6366f1,240                backgroundColor: 0xffffff,241                size: 0.8242            });243        } catch (e) {244            console.error('Vanta.js initialization failed:', e);245            document.getElementById('vanta-bg').style.backgroundColor = '#6366f1';246        }247// Initialize feather icons248        feather.replace();249        // Tab switching functionality250        const youtubeTab = document.getElementById('youtube-tab');251        const tiktokTab = document.getElementById('tiktok-tab');252        253        function switchToYoutube() {254            youtubeTab.classList.add('active-tab', 'text-primary', 'dark:text-primary', 'border-primary');255            tiktokTab.classList.remove('active-tab', 'text-primary', 'dark:text-primary', 'border-primary');256            document.getElementById('video-url').placeholder = 'https://www.youtube.com/watch?v=...';257        }258 259        function switchToTiktok() {260            tiktokTab.classList.add('active-tab', 'text-primary', 'dark:text-primary', 'border-primary');261            youtubeTab.classList.remove('active-tab', 'text-primary', 'dark:text-primary', 'border-primary');262            document.getElementById('video-url').placeholder = 'https://www.tiktok.com/@username/video/...';263        }264 265        youtubeTab.addEventListener('click', switchToYoutube);266        tiktokTab.addEventListener('click', switchToTiktok);267 268        // Set initial active tab269        switchToYoutube();270// Transcript generation271        document.getElementById('generate-btn').addEventListener('click', async (e) => {272            e.preventDefault();273            const url = document.getElementById('video-url').value.trim();274            const urlPatterns = {275                youtube: /^(https?:\/\/)?(www\.)?(youtube\.com|youtu\.?be)\/.+/,276                tiktok: /^(https?:\/\/)?(www\.)?tiktok\.com\/.+\/video\/.+/277            };278            279            if (!url) {280                alert('Please enter a valid YouTube or TikTok URL');281                return;282            }283 284            if (!urlPatterns.youtube.test(url) && !urlPatterns.tiktok.test(url)) {285                alert('Please enter a valid YouTube or TikTok URL');286                return;287            }288 289            // More detailed validation290            try {291                new URL(url);292            } catch (e) {293                alert('Invalid URL format. Please check and try again.');294                return;295            }296try {297                // Show loading state298                document.getElementById('empty-state').classList.add('hidden');299                document.getElementById('status-container').classList.remove('hidden');300                document.getElementById('results-container').classList.add('hidden');301                document.getElementById('generate-btn').disabled = true;302                document.getElementById('generate-btn').innerHTML = '<i data-feather="loader" class="animate-spin w-5 h-5"></i> Processing...';303                feather.replace();304                // Simulate API call with timeout305                const timeoutPromise = new Promise((_, reject) => 306                    setTimeout(() => reject(new Error('Request timeout')), 10000)307                );308 309                // Show loading immediately310                document.getElementById('status-text').textContent = 'Connecting to API...';311 312                const apiPromise = Promise.all([313                    fetchVideoInfo(url),314                    fetchTranscript(url)315                ]);316 317                const [videoInfo, transcriptData] = await Promise.race([apiPromise, timeoutPromise]);318                console.log('API response received:', {videoInfo, transcriptData});319// Update UI320                document.getElementById('status-container').classList.add('hidden');321                document.getElementById('results-container').classList.remove('hidden');322                // Update video info section323                const videoInfoSection = document.getElementById('video-info');324                videoInfoSection.innerHTML = `325                    <div>326                        <p class="text-sm text-gray-500 dark:text-gray-400">Title:</p>327                        <p id="video-title" class="font-medium">${videoInfo.title || 'Unknown'}</p>328                    </div>329                    <div>330                        <p class="text-sm text-gray-500 dark:text-gray-400">Duration:</p>331                        <p id="video-duration" class="font-medium">${videoInfo.duration || 'Unknown'}</p>332                    </div>333                    <div>334                        <p class="text-sm text-gray-500 dark:text-gray-400">Word Count:</p>335                        <p id="word-count" class="font-medium">${countWords(formatTranscript(transcriptData))}</p>336                    </div>337                    <div class="pt-4 border-t border-gray-200 dark:border-gray-600">338                        <p class="text-sm text-gray-500 dark:text-gray-400">Processing Time:</p>339                        <p id="processing-time" class="font-medium">${videoInfo.processingTime || 'Unknown'}</p>340                    </div>341                `;342                343                // Update transcript with better formatting344                const fullTranscript = formatTranscript(transcriptData);345                const transcriptContainer = document.getElementById('transcript-content');346                transcriptContainer.innerHTML = fullTranscript;347                348                // Add copy handler to new content349                document.getElementById('copy-btn').onclick = null;350                document.getElementById('copy-btn').addEventListener('click', copyTranscript);351} catch (error) {352                console.error('Error:', error);353                document.getElementById('status-container').classList.add('hidden');354                document.getElementById('results-container').classList.add('hidden');355                document.getElementById('empty-state').classList.remove('hidden');356                357                const errorMessage = error.message.includes('timeout') 358                    ? 'The request timed out. Please check your connection and try again.'359                    : 'Error processing video. Please try again.';360                361                alert(errorMessage);362            } finally {363                document.getElementById('generate-btn').disabled = false;364                document.getElementById('generate-btn').innerHTML = '<i data-feather="play" class="w-5 h-5"></i> Generate Transcript';365                feather.replace();366            }367});368        // Helper functions369        async function fetchVideoInfo(url) {370            // Mock implementation with better error handling371            return new Promise((resolve, reject) => {372                setTimeout(() => {373                    try {374                        // Simulate occasional failure375                        if (Math.random() < 0.1) {376                            throw new Error('Random API failure simulation');377                        }378                        379                        resolve({380                            title: 'Sample Video Title',381                            duration: '5:30',382                            processingTime: `${(Math.random() * 2 + 1).toFixed(2)} seconds`383                        });384                    } catch (error) {385                        console.error('fetchVideoInfo error:', error);386                        reject(error);387                    }388                }, 500);389            });390        }391 392        async function fetchTranscript(url) {393            // Mock implementation with better error handling394            return new Promise((resolve, reject) => {395                setTimeout(() => {396                    try {397                        // Simulate occasional failure398                        if (Math.random() < 0.1) {399                            throw new Error('Random API failure simulation');400                        }401                        402                        const mockTranscript = [];403                        for (let i = 0; i < 10; i++) {404                            mockTranscript.push({405                                timestamp: `00:${i.toString().padStart(2, '0')}`,406                                text: `This is sample transcript line ${i + 1} for demonstration purposes.`407                            });408                        }409                        resolve(mockTranscript);410                    } catch (error) {411                        console.error('fetchTranscript error:', error);412                        reject(error);413                    }414                }, 1000);415            });416        }417function formatTranscript(data) {418            return data.map(entry => 419                `<p><strong>[${entry.timestamp}]</strong> ${entry.text}</p>`420            ).join('');421        }422 423        function countWords(text) {424            return text.split(/\s+/).filter(word => word.length > 0).length;425        }426        // Copy functionality with fallback427        document.getElementById('copy-btn').addEventListener('click', async () => {428            const transcriptText = document.getElementById('transcript-content').textContent;429            const copyBtn = document.getElementById('copy-btn');430            431            try {432                if (navigator.clipboard) {433                    await navigator.clipboard.writeText(transcriptText);434                } else {435                    // Fallback for older browsers436                    const textArea = document.createElement('textarea');437                    textArea.value = transcriptText;438                    document.body.appendChild(textArea);439                    textArea.select();440                    document.execCommand('copy');441                    document.body.removeChild(textArea);442                }443                444                const originalText = copyBtn.innerHTML;445                copyBtn.innerHTML = '<i data-feather="check" class="w-4 h-4"></i> Copied!';446                copyBtn.classList.add('bg-green-500', 'hover:bg-green-600');447                feather.replace();448                449                setTimeout(() => {450                    copyBtn.innerHTML = originalText;451                    copyBtn.classList.remove('bg-green-500', 'hover:bg-green-600');452                    feather.replace();453                }, 2000);454            } catch (err) {455                console.error('Failed to copy:', err);456                alert('Failed to copy transcript. Please try again or copy manually.');457            }458        });459// Download functionality460        document.getElementById('download-btn').addEventListener('click', () => {461            const transcriptText = document.getElementById('transcript-content').textContent;462            const blob = new Blob([transcriptText], { type: 'text/plain' });463            const url = URL.createObjectURL(blob);464            const a = document.createElement('a');465            a.href = url;466            a.download = 'transcript.txt';467            document.body.appendChild(a);468            a.click();469            document.body.removeChild(a);470            URL.revokeObjectURL(url);471        });472        // Dark mode detection and toggle with local storage473        function initDarkMode() {474            const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;475            const storedMode = localStorage.getItem('darkMode');476            477            if (storedMode === 'dark' || (storedMode === null && prefersDark)) {478                document.documentElement.classList.add('dark');479            }480            481            const darkModeToggle = document.createElement('button');482            darkModeToggle.className = 'fixed top-4 right-4 bg-gray-200 dark:bg-gray-700 p-2 rounded-full z-50 transition-all';483            darkModeToggle.setAttribute('aria-label', 'Toggle dark mode');484            darkModeToggle.innerHTML = document.documentElement.classList.contains('dark') 485                ? '<i data-feather="sun" class="w-5 h-5"></i>' 486                : '<i data-feather="moon" class="w-5 h-5"></i>';487            document.body.insertBefore(darkModeToggle, document.body.firstChild);488            489            darkModeToggle.addEventListener('click', () => {490                const isDark = document.documentElement.classList.toggle('dark');491                localStorage.setItem('darkMode', isDark ? 'dark' : 'light');492                493                const icon = darkModeToggle.querySelector('i');494                icon.setAttribute('data-feather', isDark ? 'sun' : 'moon');495                feather.replace();496            });497        }498 499        // Initialize dark mode after DOM is loaded500        document.addEventListener('DOMContentLoaded', initDarkMode);501        // Global error handling502        window.addEventListener('error', function(e) {503            console.error('Error:', e.message, 'in', e.filename, 'line', e.lineno);504            505            // Hide any loading states506            document.getElementById('status-container')?.classList.add('hidden');507            document.getElementById('generate-btn').disabled = false;508            document.getElementById('generate-btn').innerHTML = '<i data-feather="play" class="w-5 h-5"></i> Generate Transcript';509            510            // Show error message511            const errorDiv = document.createElement('div');512            errorDiv.className = 'fixed top-4 left-1/2 transform -translate-x-1/2 bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded z-50 flex items-center gap-2';513            errorDiv.innerHTML = `514                <i data-feather="alert-triangle" class="w-5 h-5"></i>515                <span>Something went wrong. Please try again.</span>516            `;517            document.body.appendChild(errorDiv);518            feather.replace();519            520            setTimeout(() => {521                errorDiv.classList.add('opacity-0', 'transition-opacity', 'duration-300');522                setTimeout(() => errorDiv.remove(), 300);523            }, 5000);524        });525        // Initialize with loading states and button handlers526        document.addEventListener('DOMContentLoaded', () => {527            feather.replace();528            document.getElementById('empty-state').classList.remove('hidden');529            530            // Ensure button handlers are properly attached531            document.getElementById('generate-btn').onclick = null;532            document.getElementById('generate-btn').addEventListener('click', generateTranscript);533            534            document.getElementById('copy-btn').onclick = null;535            document.getElementById('copy-btn').addEventListener('click', copyTranscript);536            537            document.getElementById('download-btn').onclick = null;538            document.getElementById('download-btn').addEventListener('click', downloadTranscript);539        });540 541        // Named functions for better debugging542        async function generateTranscript() {543            const url = document.getElementById('video-url').value.trim();544            // ... rest of the generate functionality ...545        }546 547        async function copyTranscript() {548            // ... copy functionality ...549        }550 551        function downloadTranscript() {552            // ... download functionality ...553        }554feather.replace();555    </script>556</body>557</html>558