Spaces:
Sleeping
Sleeping
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Moody Lyrics</title> | |
<style> | |
@import url('https://fonts.googleapis.com/css2?family=Lora:wght@400;700&family=Playfair+Display:wght@400;700&display=swap'); | |
body { | |
font-family: 'Lora', serif; | |
background: linear-gradient(135deg, #f3ec78, #af4261); | |
color: #333; | |
margin: 0; | |
padding: 0; | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
height: 100vh; | |
transition: background 1s ease-in-out; /* Smooth gradient transition */ | |
} | |
.container { | |
background: rgba(255, 255, 255, 0.9); | |
padding: 30px; | |
border-radius: 20px; | |
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); | |
max-width: 700px; | |
width: 100%; | |
text-align: center; | |
overflow-y: auto; | |
max-height: 90vh; | |
transition: background-color 0.5s ease-in-out; | |
display: flex; | |
flex-direction: column; | |
gap: 20px; | |
} | |
h1 { | |
color: #2c3e50; | |
font-size: 2.5em; | |
margin-bottom: 20px; | |
font-family: 'Playfair Display', serif; | |
} | |
form { | |
display: flex; | |
flex-direction: column; | |
align-items: center; | |
gap: 20px; | |
} | |
input[type="text"] { | |
padding: 15px; | |
width: 80%; | |
border: 2px solid #2c3e50; | |
border-radius: 10px; | |
font-size: 1em; | |
transition: border-color 0.3s; | |
font-family: 'Lora', serif; | |
} | |
input[type="text"]:focus { | |
border-color: #2980b9; | |
outline: none; | |
} | |
button { | |
padding: 15px 40px; | |
background-color: #af4261; | |
color: #fff; | |
border: none; | |
border-radius: 10px; | |
font-size: 1.2em; | |
cursor: pointer; | |
transition: background-color 0.3s, transform 0.3s; | |
font-family: 'Lora', serif; | |
} | |
button:hover { | |
background-color: #f3ec78; | |
color: #af4261; | |
transform: translateY(-2px); | |
} | |
#mood-result { | |
margin-top: 20px; | |
font-size: 1.5em; | |
color: #2980b9; | |
} | |
#mood-chart { | |
max-width: 100%; | |
height: 300px; | |
} | |
pre { | |
background: rgba(244, 244, 249, 0.9); | |
padding: 20px; | |
border-radius: 10px; | |
white-space: pre-wrap; | |
word-wrap: break-word; | |
margin-top: 20px; | |
font-family: 'Courier New', Courier, monospace; | |
text-align: left; | |
transition: background-color 0.5s ease-in-out; | |
} | |
#results-container { | |
margin-top: 20px; | |
padding: 20px; | |
border-radius: 10px; | |
transition: background-color 0.5s ease-in-out; | |
} | |
.footer { | |
margin-top: 20px; | |
font-size: 0.9em; | |
color: #555; | |
text-align: center; | |
} | |
#more-info { | |
display: none; | |
max-height: 0; | |
overflow: hidden; | |
transition: max-height 0.5s ease-out, opacity 0.5s ease-out; | |
opacity: 0; | |
text-align: left; | |
font-size: 0.9em; | |
color: #333; | |
padding: 20px; | |
border-radius: 10px; | |
background: rgba(244, 244, 249, 0.9); | |
} | |
#more-info.show { | |
display: block; | |
max-height: 500px; /* Adjust as needed */ | |
opacity: 1; | |
} | |
#more-info-link { | |
color: #333; /* Match the rest of the text color */ | |
cursor: pointer; | |
text-decoration: underline; | |
} | |
.spinner { | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
height: 100px; | |
margin-top: 20px; | |
} | |
.spinner-border { | |
width: 3rem; | |
height: 3rem; | |
border: 0.3em solid rgba(0, 0, 0, 0.1); | |
border-radius: 50%; | |
border-top-color: #af4261; | |
animation: spin 0.75s linear infinite; | |
} | |
@keyframes spin { | |
to { transform: rotate(360deg); } | |
} | |
#accuracy-test { | |
display: none; | |
margin-top: 20px; | |
text-align: center; | |
} | |
#accuracy-test button { | |
padding: 10px 20px; | |
margin: 0 10px; | |
font-size: 1em; | |
cursor: pointer; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="container"> | |
<h1>Moody Lyrics</h1> | |
<form id="mood-form"> | |
<input type="text" id="title" placeholder="Song Title" required> | |
<input type="text" id="artist" placeholder="Artist" required> | |
<button type="submit">Predict Mood</button> | |
</form> | |
<div id="results-container"> | |
<h2 id="mood-result"></h2> | |
<div id="spinner" class="spinner" style="display: none;"> | |
<div class="spinner-border" role="status"></div> | |
</div> | |
<canvas id="mood-chart"></canvas> | |
<pre id="lyrics"></pre> | |
<!-- Feedback and Accuracy Test --> | |
<div id="accuracy-test"> | |
<p>Did the model get the mood right?</p> | |
<button id="correct" title="Yes">Yes</button> | |
<button id="incorrect" title="No">No</button> | |
</div> | |
</div> | |
<div class="footer"> | |
This app analyzes song lyrics to predict their mood. Enter a song title and artist, and get mood predictions along with the lyrics. Deployed using Hugging Face Spaces. The model may be inaccurate in some cases. | |
<br><br> | |
<a href="#" id="more-info-link">Learn more.</a> | |
<div id="more-info"> | |
<p><strong>How it Works:</strong></p> | |
<p>This web app utilizes a fine-tuned BERT model to analyze the mood of song lyrics. Upon entering a song title and artist, the app retrieves the song's lyrics from Genius, processes them through the BERT model, and predicts the mood. The model's accuracy is 93% on its test set.</p> | |
<p><strong>Technology:</strong></p> | |
<ul> | |
<li><strong>Model:</strong> BERT (Bidirectional Encoder Representations from Transformers) fine-tuned on song lyrics to classify moods.</li> | |
<li><strong>Framework:</strong> PyTorch and Hugging Face Transformers library for model training and prediction.</li> | |
<li><strong>Frontend:</strong> HTML, CSS, and JavaScript.</li> | |
<li><strong>Backend:</strong> Flask.</li> | |
<li><strong>Deployment:</strong> The web app is hosted and deployed using Hugging Face Spaces, which provides a simple interface for serving machine learning models.</li> | |
</ul> | |
<p>For the source code, visit: <a href="https://github.com/ggopalai/moody-lyrics/tree/master" target="_blank">GitHub Repository</a></p> | |
</div> | |
</div> | |
</div> | |
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> | |
<script> | |
// Initialize the chart with zero probabilities | |
const ctx = document.getElementById('mood-chart').getContext('2d'); | |
let moodChart = new Chart(ctx, { | |
type: 'bar', | |
data: { | |
labels: ['Angry', 'Happy', 'Relaxed', 'Sad'], | |
datasets: [{ | |
label: 'Mood Probabilities', | |
data: [0, 0, 0, 0], // Initial data | |
backgroundColor: [ | |
'rgba(255, 99, 132, 0.2)', | |
'rgba(255, 159, 64, 0.2)', | |
'rgba(75, 192, 192, 0.2)', | |
'rgba(153, 102, 255, 0.2)' | |
], | |
borderColor: [ | |
'rgba(255, 99, 132, 1)', | |
'rgba(255, 159, 64, 1)', | |
'rgba(75, 192, 192, 1)', | |
'rgba(153, 102, 255, 1)' | |
], | |
borderWidth: 1 | |
}] | |
}, | |
options: { | |
scales: { | |
y: { | |
beginAtZero: true, | |
min: 0, | |
max: 1, | |
ticks: { | |
stepSize: 0.1, | |
callback: function(value) { return value.toFixed(1); } // Format y-axis labels | |
} | |
} | |
} | |
} | |
}); | |
document.getElementById('mood-form').addEventListener('submit', async function(event) { | |
event.preventDefault(); | |
const title = document.getElementById('title').value; | |
const artist = document.getElementById('artist').value; | |
// Show the spinner | |
document.getElementById('spinner').style.display = 'flex'; | |
const response = await fetch('/predict', { | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json', | |
}, | |
body: JSON.stringify({ title, artist }), | |
}); | |
const data = await response.json(); | |
document.getElementById('mood-result').innerText = `Predicted Mood: ${data.mood}`; | |
document.getElementById('lyrics').innerText = data.lyrics; | |
// Hide the spinner | |
document.getElementById('spinner').style.display = 'none'; | |
// Scroll to the top of the container to ensure the form remains visible | |
document.querySelector('.container').scrollTop = 0; | |
// Change background color based on the predicted mood | |
const resultsContainer = document.getElementById('results-container'); | |
const body = document.body; | |
switch (data.mood.toLowerCase()) { | |
case 'happy': | |
resultsContainer.style.backgroundColor = '#fff9c4'; // light yellow | |
body.style.background = 'linear-gradient(135deg, #fff9c4, #f39c12)'; // gradient for happy | |
break; | |
case 'angry': | |
resultsContainer.style.backgroundColor = '#ffcdd2'; // light red | |
body.style.background = 'linear-gradient(135deg, #ffcdd2, #e74c3c)'; // gradient for angry | |
break; | |
case 'relaxed': | |
resultsContainer.style.backgroundColor = '#c8e6c9'; // light green | |
body.style.background = 'linear-gradient(135deg, #c8e6c9, #27ae60)'; // gradient for relaxed | |
break; | |
case 'sad': | |
resultsContainer.style.backgroundColor = '#bbdefb'; // light blue | |
body.style.background = 'linear-gradient(135deg, #bbdefb, #3498db)'; // gradient for sad | |
break; | |
default: | |
resultsContainer.style.backgroundColor = 'rgba(244, 244, 249, 0.9)'; // default background color | |
body.style.background = 'linear-gradient(135deg, #f3ec78, #af4261)'; // default gradient | |
} | |
// Update chart with new data | |
moodChart.data.datasets[0].data = data.probabilities || [0, 0, 0, 0]; | |
moodChart.update(); | |
// Show feedback section | |
document.getElementById('accuracy-test').style.display = 'block'; | |
}); | |
// Toggle detailed description with smooth effect and scroll to it | |
document.getElementById('more-info-link').addEventListener('click', function(event) { | |
event.preventDefault(); | |
const moreInfo = document.getElementById('more-info'); | |
if (moreInfo.style.display === 'none' || !moreInfo.style.display) { | |
moreInfo.style.display = 'block'; | |
setTimeout(() => { | |
moreInfo.classList.add('show'); | |
// Scroll to the more-info section smoothly | |
moreInfo.scrollIntoView({ behavior: 'smooth', block: 'start' }); | |
}, 10); | |
} else { | |
moreInfo.classList.remove('show'); | |
setTimeout(() => moreInfo.style.display = 'none', 500); | |
} | |
}); | |
// Handle accuracy test | |
document.getElementById('correct').addEventListener('click', function() { | |
alert('Thank you for the feedback!'); | |
// Send correct feedback to the server if needed | |
}); | |
document.getElementById('incorrect').addEventListener('click', function() { | |
alert('Thank you for the feedback!'); | |
// Send incorrect feedback to the server if needed | |
}); | |
</script> | |
</body> | |
</html> | |