Spaces:
Sleeping
Sleeping
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8" /> | |
| <meta name="viewport" content="width=device-width,initial-scale=1" /> | |
| <title>Speech DeepFake detection </title> | |
| <!-- Bootstrap for quick UI --> | |
| <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet"> | |
| <!-- WaveSurfer --> | |
| <script src="https://unpkg.com/wavesurfer.js"></script> | |
| <style> | |
| :root{ | |
| --accent:#ff5500; /* SoundCloud-esque orange */ | |
| --muted:#6c757d; | |
| --card-bg: #ffffff; | |
| --page-bg: #fbfbfc; | |
| } | |
| body{ | |
| background: linear-gradient(180deg, #fbfbfc 0%, #f6f7f9 100%); | |
| font-family: Inter, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial; | |
| padding: 28px; | |
| color:#222; | |
| } | |
| .app { | |
| max-width: 960px; | |
| margin: 0 auto; | |
| background: var(--card-bg); | |
| border-radius: 12px; | |
| box-shadow: 0 8px 30px rgba(34,41,47,0.06); | |
| padding: 26px; | |
| } | |
| h1 { color:#111; font-weight:700; margin-bottom:6px; } | |
| p.lead { color:var(--muted); margin-top:0; } | |
| /* Controls */ | |
| .control-row { display:flex; gap:10px; flex-wrap:wrap; align-items:center; } | |
| #formats { color:var(--muted); font-size:0.95rem; } | |
| /* Wave card (SoundCloud-like compact list) */ | |
| .wave-item{ | |
| display:flex; | |
| gap:14px; | |
| align-items:center; | |
| padding:12px; | |
| border-radius:10px; | |
| background: linear-gradient(90deg, rgba(255,255,255,0.6), rgba(250,250,251,0.6)); | |
| border:1px solid #eee; | |
| margin-bottom:12px; | |
| } | |
| .wave-meta { min-width:160px; max-width:220px; } | |
| .file-title { font-weight:600; color:#111; margin-bottom:6px; } | |
| .wave-canvas { flex:1; min-width:240px; } | |
| .wave-controls{ display:flex; gap:8px; align-items:center; } | |
| .btn-play{ | |
| background: var(--accent); | |
| border: none; | |
| color: #fff; | |
| } | |
| .small-muted { color:var(--muted); font-size:0.9rem; } | |
| /* Analysis & metadata panels */ | |
| .panel { margin-top:18px; padding:12px; border-radius:8px; background:#fafafa; border:1px solid #eee; } | |
| .response pre{ white-space:pre-wrap; word-break:break-word; } | |
| input[type="file"] { padding:4px; } | |
| /* Make waves visually similar to SoundCloud: subtle rounded waves and orange progress */ | |
| .wavesurfer .wave { border-radius:4px; overflow:hidden; } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="app"> | |
| <div class="d-flex justify-content-between align-items-start mb-3"> | |
| <div> | |
| <h1>Speech DeepFake detection</h1> | |
| <p class="lead">Record audio, upload WAV/FLAC, preview waveform, analyze.</p> | |
| </div> | |
| <div class="text-end small-muted"> | |
| <div>Format: <span id="formats">—</span></div> | |
| </div> | |
| </div> | |
| <!-- Upload section: upload button inline with file input --> | |
| <div class="panel mb-3"> | |
| <label class="form-label">Upload audio files</label> | |
| <div class="d-flex gap-2 align-items-center"> | |
| <input id="audio-file" type="file" class="form-control" accept="audio/*,.wav" multiple /> | |
| <button id="upload-button" type="button" class="btn btn-outline-primary">Upload</button> | |
| </div> | |
| </div> | |
| <!-- Recorder --> | |
| <div class="panel mt-3"> | |
| <div class="mb-2"><strong>Record audio</strong></div> | |
| <div class="control-row"> | |
| <button id="recordButton" class="btn btn-success">Start recording</button> | |
| <button id="pauseButton" class="btn btn-warning" disabled>Pause</button> | |
| <button id="stopButton" class="btn btn-danger" disabled>Stop</button> | |
| <div class="small-muted ms-2">Recorded files appear below with waveform preview</div> | |
| </div> | |
| </div> | |
| <!-- Recordings List --> | |
| <div class="mt-3"> | |
| <div class="d-flex justify-content-between align-items-center mb-2"> | |
| <h5 class="m-0">Recorded & Uploaded files</h5> | |
| <!-- NEW: Clear Button --> | |
| <button id="clearButton" class="btn btn-sm btn-outline-secondary">Clear All</button> | |
| </div> | |
| <ol id="recordingsList" class="list-unstyled p-0"></ol> | |
| </div> | |
| <!-- Analysis / Metadata --> | |
| <div class="response mt-3"> | |
| <h3>Analysis Results</h3> | |
| <div id="response"></div> | |
| </div> | |
| </div> | |
| <!-- Use the uploaded recorder.js and script.js files from your workspace --> | |
| <script src="/static/recorder.js"></script> | |
| <script src="/static/script.js"></script> | |
| <!-- small inline initializer to ensure script.js hooks run after DOM loads --> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', () => { | |
| const formatsEl = document.getElementById('formats'); | |
| // Initial format text | |
| if (formatsEl) { | |
| formatsEl.textContent = 'Ready — click Record or Upload a file'; | |
| } | |
| // Logic for the Clear Button | |
| const clearBtn = document.getElementById('clearButton'); | |
| if (clearBtn) { | |
| clearBtn.addEventListener('click', () => { | |
| // Clear the list of recordings | |
| const list = document.getElementById('recordingsList'); | |
| if (list) list.innerHTML = ''; | |
| // Clear the analysis text | |
| const response = document.getElementById('response'); | |
| if (response) response.innerHTML = ''; | |
| // Reset the file input so the same file can be uploaded again if needed | |
| const fileInput = document.getElementById('audio-file'); | |
| if (fileInput) fileInput.value = ''; | |
| }); | |
| } | |
| }); | |
| </script> | |
| </body> | |
| </html> |