|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8" /> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
|
<title>Emojiifier</title> |
|
<script nonce="<%= nonce %>" src="/static/script.js"></script> |
|
<link |
|
rel="stylesheet" |
|
href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" |
|
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" |
|
crossorigin="anonymous" |
|
/> |
|
<link |
|
href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400;600;700&display=swap" |
|
rel="stylesheet" |
|
/> |
|
<link |
|
rel="stylesheet" |
|
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" |
|
integrity="sha512-iBBXm8fW90+nuLcSKlbmrPcLa0OT92xO1BIsZ+ywDWZCvqsWgccV3gFoRBv0z+8dLJgyAHIhR35VZc2oM/gI1w==" |
|
crossorigin="anonymous" |
|
/> |
|
<style nonce="<%= nonce %>"> |
|
body { |
|
background-color: rgb(255, 187, 0); |
|
} |
|
|
|
.navbar { |
|
transition: transform 0.3s ease-in-out, padding 0.3s ease-in-out, |
|
background-color 0.3s ease-in-out; |
|
padding: 1rem 2rem; |
|
background-color: #ffdc6b; |
|
border: black 2px solid; |
|
border-radius: 30px; |
|
width: 100%; |
|
margin: 0 auto; |
|
transform: scale(1); |
|
position: relative; |
|
padding-left: 20px; |
|
padding-right: 20px; |
|
} |
|
|
|
.navbar.scrolled { |
|
padding: 0.5rem 2rem; |
|
border-radius: 0; |
|
width: 100%; |
|
position: fixed; |
|
top: 0; |
|
left: 0; |
|
background-color: #ffffff6e; |
|
backdrop-filter: blur(3px); |
|
-webkit-backdrop-filter: blur(3px); |
|
border: none !important; |
|
} |
|
|
|
.navbar-brand { |
|
transition: transform 1s ease-in-out; |
|
position: absolute; |
|
left: 50%; |
|
transform: translateX(-50%); |
|
} |
|
|
|
.navbar.scrolled .navbar-brand { |
|
transform: translateX(-50%) scale(0.8); |
|
} |
|
|
|
.content-area { |
|
width: 100vw; |
|
height: calc(90vh); |
|
padding: 20px; |
|
} |
|
|
|
@keyframes emojiChange { |
|
0% { |
|
content: "π"; |
|
} |
|
25% { |
|
content: "π"; |
|
} |
|
50% { |
|
content: "π€ͺ"; |
|
} |
|
75% { |
|
content: "π₯³"; |
|
} |
|
100% { |
|
content: "π"; |
|
} |
|
} |
|
|
|
.emoji-text::after { |
|
content: "π"; |
|
animation: emojiChange 4s infinite; |
|
} |
|
|
|
.spacer { |
|
margin-top: 13.6vh; |
|
} |
|
|
|
.content-wrapper { |
|
margin-top: -13.6vh; |
|
} |
|
|
|
.main-content { |
|
width: 95%; |
|
margin: 0 auto; |
|
min-height: calc(100vh - 13.6vh); |
|
} |
|
|
|
.bg-light-gray { |
|
background-color: #f0f0f0; |
|
min-height: 70vh; |
|
border-top-left-radius: 30px !important; |
|
border-bottom-left-radius: 30px; |
|
} |
|
|
|
.bg-dark-red { |
|
background-color: #324376; |
|
color: white; |
|
min-height: 70vh; |
|
border-top-right-radius: 30px; |
|
border-bottom-right-radius: 30px; |
|
} |
|
|
|
.webcam-video { |
|
object-fit: cover; |
|
border-top-left-radius: 30px !important; |
|
border-bottom-left-radius: 30px; |
|
} |
|
|
|
.instructions-container { |
|
padding: 1.5rem; |
|
background-color: rgba(255, 255, 255, 0.043); |
|
border-radius: 20px; |
|
margin: 1rem; |
|
height: calc(100% - 2rem); |
|
display: flex; |
|
flex-direction: column; |
|
} |
|
|
|
.instructions-container h1 { |
|
font-size: 1.6rem; |
|
font-weight: 600; |
|
margin-bottom: 1rem; |
|
color: #ffc857; |
|
} |
|
|
|
.instructions-container h2, |
|
.instructions-container h3 { |
|
font-size: 1.1rem; |
|
font-weight: 500; |
|
color: #ffb627; |
|
margin-top: 0.8rem; |
|
} |
|
|
|
.instructions-container ul { |
|
margin-left: 0; |
|
padding-left: 0; |
|
} |
|
|
|
.instructions-container li { |
|
margin-bottom: 0.6rem; |
|
font-size: 0.95rem; |
|
line-height: 1.4; |
|
color: #f0f0f0; |
|
} |
|
|
|
.instructions-container p { |
|
color: #ffb627; |
|
font-weight: 500; |
|
} |
|
|
|
.capture-btn { |
|
margin-top: auto; |
|
background-color: #ffc857; |
|
color: #15224b; |
|
border: none; |
|
padding: 1rem; |
|
border-radius: 10px; |
|
font-weight: 600; |
|
transition: all 0.3s ease; |
|
opacity: 1; |
|
} |
|
|
|
.capture-btn:hover { |
|
background-color: #ffb627; |
|
transform: scale(1.02); |
|
} |
|
|
|
.calculating-container { |
|
display: none; |
|
text-align: center; |
|
height: 100%; |
|
justify-content: center; |
|
align-items: center; |
|
flex-direction: column; |
|
} |
|
|
|
.calculating-text { |
|
font-size: 2rem; |
|
color: #ffc857; |
|
margin-bottom: 2rem; |
|
} |
|
|
|
.result-emoji { |
|
font-size: 8rem; |
|
margin-bottom: 1rem; |
|
animation: pulse 2s infinite; |
|
} |
|
|
|
.result-comment { |
|
font-size: 1.2rem; |
|
color: #f0f0f0; |
|
} |
|
|
|
@keyframes bounce { |
|
0%, |
|
20%, |
|
50%, |
|
80%, |
|
100% { |
|
transform: translateY(0); |
|
} |
|
40% { |
|
transform: translateY(-20px); |
|
} |
|
60% { |
|
transform: translateY(-10px); |
|
} |
|
} |
|
|
|
@keyframes pulse { |
|
0% { |
|
transform: scale(1); |
|
} |
|
50% { |
|
transform: scale(1.1); |
|
} |
|
100% { |
|
transform: scale(1); |
|
} |
|
} |
|
|
|
@keyframes spin { |
|
0% { |
|
transform: rotate(0deg); |
|
} |
|
100% { |
|
transform: rotate(360deg); |
|
} |
|
} |
|
|
|
.loading-spinner { |
|
width: 50px; |
|
height: 50px; |
|
border: 5px solid #f3f3f3; |
|
border-top: 5px solid #ffc857; |
|
border-radius: 50%; |
|
animation: spin 1s linear infinite; |
|
margin: 20px auto; |
|
} |
|
|
|
.bounce { |
|
animation: bounce 2s infinite; |
|
} |
|
|
|
#capturedImage { |
|
display: none; |
|
width: 100%; |
|
height: 100%; |
|
object-fit: cover; |
|
border-top-left-radius: 30px !important; |
|
border-bottom-left-radius: 30px; |
|
} |
|
|
|
.technical-section { |
|
background-color: #324376; |
|
color: white; |
|
padding: 4rem 2rem; |
|
} |
|
|
|
.technical-section h2 { |
|
color: #ffc857; |
|
margin-bottom: 2rem; |
|
} |
|
|
|
.step-box { |
|
background: rgba(255, 255, 255, 0.1); |
|
border-radius: 10px; |
|
padding: 1.5rem; |
|
margin-bottom: 1.5rem; |
|
} |
|
|
|
.step-box h3 { |
|
color: #ffb627; |
|
margin-bottom: 1rem; |
|
} |
|
|
|
.step-box p { |
|
color: #f0f0f0; |
|
line-height: 1.6; |
|
} |
|
|
|
.code-block { |
|
background: #1e2a4a; |
|
padding: 1rem; |
|
border-radius: 5px; |
|
margin: 1rem 0; |
|
font-family: monospace; |
|
} |
|
|
|
.probability-bar { |
|
height: 20px; |
|
background: #ffc857; |
|
border-radius: 10px; |
|
margin: 5px 0; |
|
} |
|
|
|
.probability-label { |
|
display: flex; |
|
justify-content: space-between; |
|
color: #f0f0f0; |
|
margin-bottom: 5px; |
|
} |
|
|
|
.detected-emoji { |
|
font-size: 4rem; |
|
} |
|
|
|
.highlight-text { |
|
color: #ffc857; |
|
} |
|
|
|
.confidence-text { |
|
color: #ffc857; |
|
} |
|
|
|
.preprocessed-image { |
|
max-width: 100%; |
|
border-radius: 5px; |
|
} |
|
|
|
.probability-bar-custom { |
|
width: var(--percentage); |
|
} |
|
|
|
.processing-info { |
|
margin-top: 10px; |
|
font-size: 0.9em; |
|
color: #666; |
|
} |
|
|
|
.step-list { |
|
list-style: none; |
|
padding: 0; |
|
} |
|
|
|
.step-list li { |
|
padding: 5px 0; |
|
color: #f0f0f0; |
|
position: relative; |
|
padding-left: 20px; |
|
} |
|
|
|
.step-list li:before { |
|
content: "β"; |
|
position: absolute; |
|
left: 0; |
|
color: #ffc857; |
|
} |
|
|
|
.final-analysis { |
|
background: #324376 !important; |
|
border-radius: 30px !important; |
|
padding: 40px !important; |
|
margin-top: 40px; |
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); |
|
} |
|
|
|
.analysis-container { |
|
padding: 0; |
|
} |
|
|
|
.analysis-box { |
|
background: rgba(255, 255, 255, 0.05) !important; |
|
padding: 30px; |
|
border-radius: 30px; |
|
height: 100%; |
|
border: none !important; |
|
margin: 10px; |
|
text-align: center; |
|
} |
|
|
|
.analysis-box h4 { |
|
color: #f0f0f0; |
|
font-size: 1.5rem; |
|
margin-bottom: 20px; |
|
font-weight: 300; |
|
letter-spacing: 1px; |
|
} |
|
|
|
.detected-emoji { |
|
font-size: 4.5rem; |
|
margin: 15px 0; |
|
} |
|
|
|
.highlight-text { |
|
color: #ffc857; |
|
font-size: 2rem; |
|
margin-top: 15px !important; |
|
text-transform: capitalize; |
|
font-weight: 300; |
|
} |
|
|
|
.confidence-text { |
|
color: #ffc857; |
|
font-size: 2rem; |
|
font-weight: 300; |
|
} |
|
|
|
.final-analysis h3 { |
|
color: #f0f0f0; |
|
font-size: 2rem; |
|
margin-bottom: 30px; |
|
font-weight: 300; |
|
letter-spacing: 1px; |
|
} |
|
</style> |
|
</head> |
|
<body> |
|
<div class="container-fluid mt-4 fixed-top px-3"> |
|
<nav class="navbar navbar-expand navbar-light"> |
|
<div class="container-fluid"> |
|
<button |
|
id="settingsBtn" |
|
class="btn btn-link text-dark d-none d-lg-block" |
|
> |
|
<i class="fas fa-cog fa-lg"></i> |
|
</button> |
|
|
|
<a class="navbar-brand font-weight-bold" href="#"> |
|
EM<span class="emoji-text"></span>JIFIER |
|
</a> |
|
|
|
<button class="btn btn-link text-dark d-none d-lg-block"> |
|
<i class="fas fa-user fa-lg"></i> |
|
</button> |
|
</div> |
|
</nav> |
|
</div> |
|
|
|
<div class="spacer"></div> |
|
|
|
<div class="content-area"> |
|
<div class="row no-gutters camera-emoji-container"> |
|
<div class="col-md-6 w-100 vh-100 bg-light-gray"> |
|
<video |
|
id="webcam" |
|
autoplay |
|
playsinline |
|
class="w-100 h-100 webcam-video" |
|
></video> |
|
<img id="capturedImage" alt="Captured Image" /> |
|
</div> |
|
<div class="col-md-6 no-guttter w-100 vh-100 bg-dark-red"> |
|
<div class="instructions-container"> |
|
<div id="initial-content"> |
|
<h1>Welcome to our Emotion Detection Website!</h1> |
|
|
|
<h2>Getting Started:</h2> |
|
<ul class="list-unstyled"> |
|
<li> |
|
1. Allow webcam access and ensure your face is well-lit and |
|
centered |
|
</li> |
|
<li> |
|
2. Click "DETECT" to capture your image and display your |
|
emotion (e.g., Happy, Sad) |
|
</li> |
|
<li> |
|
3. Click "Show It's Working" to see how the system uses facial |
|
landmarks and SVM model analysis |
|
</li> |
|
</ul> |
|
|
|
<h3>Best Practices:</h3> |
|
<ul class="list-unstyled"> |
|
<li>β’ Ensure clear lighting</li> |
|
<li>β’ Keep face unobstructed</li> |
|
<li>β’ Check webcam permissions if issues arise</li> |
|
<li>β’ Adjust lighting if needed</li> |
|
</ul> |
|
</div> |
|
|
|
<div id="calculating-content" class="calculating-container"> |
|
<div class="loading-spinner"></div> |
|
<div class="result-emoji"></div> |
|
<div class="result-comment"></div> |
|
</div> |
|
|
|
<button id="detectBtn" class="capture-btn"> |
|
<i class="fas fa-smile mr-2"></i>Detect Emotion |
|
</button> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<div id="technical-section" class="technical-section"> |
|
<div class="container"> |
|
<h2 class="text-center mb-4">Real-Time Model Analysis</h2> |
|
|
|
<div class="step-box"> |
|
<h3>Step 1: Image Acquisition</h3> |
|
<p>Capturing and preparing your image:</p> |
|
<div id="preprocessed-image"></div> |
|
</div> |
|
|
|
<div class="step-box"> |
|
<h3>Step 2: Model Prediction</h3> |
|
<p>Confidence scores for each emotion:</p> |
|
<div id="emotion-probabilities"> |
|
|
|
</div> |
|
</div> |
|
|
|
<div class="step-box final-analysis"> |
|
<h3>Final Analysis</h3> |
|
<div class="analysis-container"> |
|
<div class="row align-items-stretch"> |
|
<div class="col-md-6"> |
|
<div class="analysis-box"> |
|
<h4>Primary Emotion</h4> |
|
<div id="primary-emotion" class="text-center"> |
|
<span id="detected-emoji" class="detected-emoji"></span> |
|
<h4 id="detected-emotion" class="highlight-text"></h4> |
|
</div> |
|
</div> |
|
</div> |
|
<div class="col-md-6"> |
|
<div class="analysis-box"> |
|
<h4>Confidence Level</h4> |
|
<div id="confidence-score" class="text-center"> |
|
<h4 class="confidence-text"></h4> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
</body> |
|
<script nonce="<%= nonce %>"> |
|
const navbar = document.querySelector(".navbar"); |
|
|
|
window.addEventListener("scroll", () => { |
|
if (window.scrollY > 10) { |
|
navbar.classList.add("scrolled"); |
|
} else { |
|
navbar.classList.remove("scrolled"); |
|
} |
|
}); |
|
|
|
|
|
function updateTechnicalSection(result) { |
|
|
|
document.getElementById("preprocessed-image").innerHTML = ` |
|
<img src="${result.grayscale_image}" alt="Preprocessed Image" class="preprocessed-image"> |
|
`; |
|
|
|
|
|
const probContainer = document.getElementById("emotion-probabilities"); |
|
probContainer.innerHTML = ""; |
|
|
|
Object.entries(result.model_probabilities).forEach( |
|
([emotion, probability]) => { |
|
const percentage = (probability * 100).toFixed(1); |
|
probContainer.innerHTML += ` |
|
<div class="probability-label"> |
|
<span>${emotion}</span> |
|
<span>${percentage}%</span> |
|
</div> |
|
<div class="probability-bar probability-bar-custom" style="--percentage: ${percentage}%"></div> |
|
`; |
|
} |
|
); |
|
|
|
|
|
document.getElementById("detected-emoji").textContent = result.emoji; |
|
document.getElementById("detected-emotion").textContent = result.emotion; |
|
|
|
|
|
const confidence = ( |
|
result.model_probabilities[result.emotion] * 100 |
|
).toFixed(1); |
|
document |
|
.getElementById("confidence-score") |
|
.querySelector("h4").textContent = `${confidence}% Confident`; |
|
} |
|
</script> |
|
<script |
|
nonce="<%= nonce %>" |
|
src="https://code.jquery.com/jquery-3.2.1.slim.min.js" |
|
integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" |
|
crossorigin="anonymous" |
|
></script> |
|
<script |
|
nonce="<%= nonce %>" |
|
src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" |
|
integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" |
|
crossorigin="anonymous" |
|
></script> |
|
<script |
|
nonce="<%= nonce %>" |
|
src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" |
|
integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" |
|
crossorigin="anonymous" |
|
></script> |
|
<script nonce="<%= nonce %>"> |
|
async function initWebcam() { |
|
try { |
|
const stream = await navigator.mediaDevices.getUserMedia({ |
|
video: true, |
|
}); |
|
const video = document.getElementById("webcam"); |
|
video.srcObject = stream; |
|
} catch (err) { |
|
console.error("Error accessing webcam:", err); |
|
} |
|
} |
|
|
|
function captureImage() { |
|
const video = document.getElementById("webcam"); |
|
const canvas = document.createElement("canvas"); |
|
canvas.width = video.videoWidth; |
|
canvas.height = video.videoHeight; |
|
canvas |
|
.getContext("2d") |
|
.drawImage(video, 0, 0, canvas.width, canvas.height); |
|
|
|
|
|
video.style.display = "none"; |
|
const capturedImage = document.getElementById("capturedImage"); |
|
capturedImage.src = canvas.toDataURL("image/png"); |
|
capturedImage.style.display = "block"; |
|
|
|
|
|
const initialContent = document.getElementById("initial-content"); |
|
const calculatingContent = document.getElementById("calculating-content"); |
|
const detectBtn = document.getElementById("detectBtn"); |
|
|
|
initialContent.style.display = "none"; |
|
calculatingContent.style.display = "flex"; |
|
detectBtn.style.opacity = "0"; |
|
|
|
return capturedImage; |
|
} |
|
|
|
initWebcam(); |
|
</script> |
|
</html> |
|
|