| | <!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> |
| |
|