Spaces:
Sleeping
Sleeping
| <html lang="vi"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <meta name="description" content="PrecisionVoice - Speech-to-Text and Speaker Diarization powered by AI"> | |
| <title>PrecisionVoice | AI Speech Transcription</title> | |
| <link rel="preconnect" href="https://fonts.googleapis.com"> | |
| <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> | |
| <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet"> | |
| <link rel="stylesheet" href="/static/css/style.css"> | |
| </head> | |
| <body> | |
| <div class="app-container"> | |
| <!-- Header --> | |
| <header class="header"> | |
| <div class="logo"> | |
| <div class="logo-icon"> | |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> | |
| <path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z" /> | |
| <path d="M19 10v2a7 7 0 0 1-14 0v-2" /> | |
| <line x1="12" y1="19" x2="12" y2="23" /> | |
| <line x1="8" y1="23" x2="16" y2="23" /> | |
| </svg> | |
| </div> | |
| <h1>PrecisionVoice</h1> | |
| </div> | |
| <p class="tagline">AI-Powered Speech Transcription with Speaker Detection</p> | |
| </header> | |
| <!-- Main Content --> | |
| <main class="main-content"> | |
| <!-- Upload Section --> | |
| <section id="upload-section" class="card upload-card"> | |
| <div class="card-header"> | |
| <h2>Upload Audio</h2> | |
| <span class="badge">Supported: {{ allowed_formats }}</span> | |
| </div> | |
| <div class="upload-zone" id="drop-zone"> | |
| <div class="upload-icon"> | |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> | |
| <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" /> | |
| <polyline points="17 8 12 3 7 8" /> | |
| <line x1="12" y1="3" x2="12" y2="15" /> | |
| </svg> | |
| </div> | |
| <p class="upload-text">Drag & drop audio file here</p> | |
| <p class="upload-subtext">or click to browse</p> | |
| <input type="file" id="file-input" accept=".mp3,.wav,.m4a,.ogg,.flac,.webm" hidden> | |
| </div> | |
| <div id="file-info" class="file-info hidden"> | |
| <div class="file-details"> | |
| <span class="file-name" id="file-name">audio.mp3</span> | |
| <span class="file-size" id="file-size">0 MB</span> | |
| </div> | |
| <button class="btn btn-clear" id="clear-btn" title="Remove file"> | |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> | |
| <line x1="18" y1="6" x2="6" y2="18" /> | |
| <line x1="6" y1="6" x2="18" y2="18" /> | |
| </svg> | |
| </button> | |
| </div> | |
| <button class="btn btn-primary" id="transcribe-btn" disabled> | |
| <span class="btn-text">Transcribe</span> | |
| <span class="btn-icon"> | |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> | |
| <polygon points="5 3 19 12 5 21 5 3" /> | |
| </svg> | |
| </span> | |
| </button> | |
| </section> | |
| <!-- Processing Section --> | |
| <section id="processing-section" class="card processing-card hidden"> | |
| <div class="processing-content"> | |
| <div class="spinner"></div> | |
| <h3>Processing Audio</h3> | |
| <p id="processing-status">Uploading file...</p> | |
| <div class="progress-bar"> | |
| <div class="progress-fill" id="progress-fill"></div> | |
| </div> | |
| <div class="timer-display" id="processing-timer">00:00</div> | |
| <p class="processing-hint">This may take a few minutes depending on audio length</p> | |
| </div> | |
| </section> | |
| <!-- Results Section --> | |
| <section id="results-section" class="card results-card hidden"> | |
| <div class="card-header"> | |
| <h2>Transcription Results</h2> | |
| <div class="result-meta"> | |
| <span id="speaker-count" class="badge">0 speakers</span> | |
| <span id="duration-info" class="badge">0:00</span> | |
| <span id="processing-time" class="badge">0.0s</span> | |
| </div> | |
| </div> | |
| <div class="download-buttons"> | |
| <a href="#" id="download-txt" class="btn btn-outline" download> | |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> | |
| <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" /> | |
| <polyline points="7 10 12 15 17 10" /> | |
| <line x1="12" y1="15" x2="12" y2="3" /> | |
| </svg> | |
| Download TXT | |
| </a> | |
| <a href="#" id="download-csv" class="btn btn-outline" download> | |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> | |
| <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" /> | |
| <polyline points="7 10 12 15 17 10" /> | |
| <line x1="12" y1="15" x2="12" y2="3" /> | |
| </svg> | |
| Download CSV | |
| </a> | |
| </div> | |
| <div class="transcript-container" id="transcript-container"> | |
| <!-- Transcript segments will be rendered here --> | |
| </div> | |
| <button class="btn btn-secondary" id="new-upload-btn"> | |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> | |
| <polyline points="1 4 1 10 7 10" /> | |
| <path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10" /> | |
| </svg> | |
| New Transcription | |
| </button> | |
| </section> | |
| <!-- Error Section --> | |
| <section id="error-section" class="card error-card hidden"> | |
| <div class="error-content"> | |
| <div class="error-icon"> | |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> | |
| <circle cx="12" cy="12" r="10" /> | |
| <line x1="15" y1="9" x2="9" y2="15" /> | |
| <line x1="9" y1="9" x2="15" y2="15" /> | |
| </svg> | |
| </div> | |
| <h3>Error</h3> | |
| <p id="error-message">An error occurred during processing.</p> | |
| <button class="btn btn-secondary" id="retry-btn">Try Again</button> | |
| </div> | |
| </section> | |
| </main> | |
| <!-- Footer --> | |
| <footer class="footer"> | |
| <p>Powered by <strong>faster-whisper</strong> & <strong>pyannote.audio</strong></p> | |
| <p class="footer-note">Max file size: {{ max_upload_mb }}MB</p> | |
| </footer> | |
| </div> | |
| <script src="/static/js/app.js"></script> | |
| </body> | |
| </html> |