Spaces:
Sleeping
Sleeping
Step 3 β Frontend
Status: TODO
Goal
A simple webpage where the user uploads an audio file, waits while Demucs processes it, then plays back both the original and the cleaned vocal track side by side.
Files to create
frontend/
βββ index.html # Upload form + audio players
βββ style.css # Basic layout and styling
βββ app.js # Handles upload, polling, and playback
How to build it
1. Create frontend/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Voice Isolation</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="card">
<h1>Voice Isolation</h1>
<p>Upload an audio file to remove background noise.</p>
<input type="file" id="fileInput" accept="audio/*">
<button id="uploadBtn">Upload & Clean</button>
<div id="status"></div>
<div class="players" id="players" hidden>
<div>
<p>Original</p>
<audio id="originalPlayer" controls></audio>
</div>
<div>
<p>Cleaned</p>
<audio id="cleanedPlayer" controls></audio>
</div>
</div>
</div>
<script src="app.js"></script>
</body>
</html>
2. Create frontend/app.js
const uploadBtn = document.getElementById('uploadBtn');
const fileInput = document.getElementById('fileInput');
const status = document.getElementById('status');
const players = document.getElementById('players');
const originalPlayer = document.getElementById('originalPlayer');
const cleanedPlayer = document.getElementById('cleanedPlayer');
uploadBtn.addEventListener('click', async () => {
const file = fileInput.files[0];
if (!file) {
status.textContent = 'Please select a file first.';
return;
}
status.textContent = 'Uploading and processing... this takes 1-3 minutes.';
players.hidden = true;
const formData = new FormData();
formData.append('file', file);
const response = await fetch('http://localhost:8000/upload', {
method: 'POST',
body: formData,
});
const data = await response.json();
originalPlayer.src = URL.createObjectURL(file);
cleanedPlayer.src = `http://localhost:8000${data.download_url}`;
players.hidden = false;
status.textContent = 'Done!';
});
3. Create frontend/style.css
body {
font-family: sans-serif;
background: #f4f4f4;
display: flex;
justify-content: center;
padding: 40px 20px;
}
.card {
background: white;
padding: 32px;
border-radius: 12px;
box-shadow: 0 2px 12px rgba(0,0,0,0.1);
max-width: 560px;
width: 100%;
}
h1 { margin-top: 0; }
input[type="file"] { display: block; margin: 16px 0; }
button {
background: #2563eb;
color: white;
border: none;
padding: 10px 20px;
border-radius: 6px;
cursor: pointer;
font-size: 16px;
}
button:hover { background: #1d4ed8; }
#status { margin: 16px 0; color: #555; }
.players {
display: flex;
flex-direction: column;
gap: 16px;
margin-top: 16px;
}
How to open it
Just open the HTML file directly in the browser β no server needed for the frontend:
xdg-open frontend/index.html # Linux
Make sure the FastAPI backend is running first:
source venv/bin/activate
uvicorn backend.main:app --reload
What the user sees
- Opens the page β sees a clean upload card
- Selects an audio file
- Clicks "Upload & Clean"
- Status shows "Processing..." while Demucs runs
- Two audio players appear: original and cleaned
- User hits play on both to compare
Notes
- The backend URL is hardcoded to
localhost:8000β update this to the live Hugging Face URL after deployment - No file type validation on the frontend yet β the backend will reject non-audio files anyway
- Processing takes 1β3 minutes on CPU β the status message sets that expectation for the user