Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Emotion Detector - Positive Vibes</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/face-api.js@0.22.2/dist/face-api.min.js"></script> | |
| <style> | |
| #video { | |
| transform: scaleX(-1); | |
| } | |
| .emoji { | |
| font-size: 2rem; | |
| margin-bottom: 0.5rem; | |
| } | |
| .pulse { | |
| animation: pulse 2s infinite; | |
| } | |
| @keyframes pulse { | |
| 0% { transform: scale(1); } | |
| 50% { transform: scale(1.1); } | |
| 100% { transform: scale(1); } | |
| } | |
| .fade-in { | |
| animation: fadeIn 1s; | |
| } | |
| @keyframes fadeIn { | |
| from { opacity: 0; } | |
| to { opacity: 1; } | |
| } | |
| .falling-smiley { | |
| position: fixed; | |
| font-size: 2rem; | |
| animation: fall linear forwards; | |
| z-index: 10; | |
| pointer-events: none; | |
| opacity: 0.8; | |
| } | |
| @keyframes fall { | |
| to { | |
| transform: translateY(100vh); | |
| opacity: 0; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-gradient-to-br from-indigo-100 to-purple-100 min-h-screen"> | |
| <div class="container mx-auto px-4 py-8"> | |
| <header class="text-center mb-8"> | |
| <h1 class="text-4xl font-bold text-indigo-800 mb-2">Emotion Detector</h1> | |
| <p class="text-lg text-purple-700">Smile for the camera and get some positive vibes!</p> | |
| </header> | |
| <div class="flex flex-col lg:flex-row gap-8 items-center justify-center"> | |
| <!-- Camera Section --> | |
| <div class="bg-white rounded-xl shadow-xl p-4 w-full max-w-md"> | |
| <div class="relative aspect-video bg-gray-200 rounded-lg overflow-hidden mb-4"> | |
| <video id="video" width="100%" height="100%" autoplay muted class="object-cover"></video> | |
| <canvas id="canvas" class="absolute top-0 left-0 w-full h-full pointer-events-none"></canvas> | |
| </div> | |
| </div> | |
| <!-- Results Section --> | |
| <div id="resultsSection" class="bg-white rounded-xl shadow-xl p-6 w-full max-w-md"> | |
| <div class="text-center mb-6"> | |
| <div id="emojiDisplay" class="emoji text-5xl mb-4"></div> | |
| <h2 id="emotionText" class="text-2xl font-bold text-indigo-800 mb-2"></h2> | |
| <p id="confidenceText" class="text-gray-600"></p> | |
| </div> | |
| <div class="bg-indigo-50 rounded-lg p-4 mb-4"> | |
| <h3 class="font-semibold text-indigo-700 mb-2">Positive Suggestion:</h3> | |
| <p id="suggestionText" class="text-indigo-900"></p> | |
| </div> | |
| <div class="bg-purple-50 rounded-lg p-4"> | |
| <h3 class="font-semibold text-purple-700 mb-2">Did you know?</h3> | |
| <p id="factText" class="text-purple-900"></p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| // DOM Elements | |
| const video = document.getElementById('video'); | |
| const canvas = document.getElementById('canvas'); | |
| const resultsSection = document.getElementById('resultsSection'); | |
| const emojiDisplay = document.getElementById('emojiDisplay'); | |
| const emotionText = document.getElementById('emotionText'); | |
| const confidenceText = document.getElementById('confidenceText'); | |
| const suggestionText = document.getElementById('suggestionText'); | |
| const factText = document.getElementById('factText'); | |
| // Emotion to emoji mapping | |
| const emotionEmojis = { | |
| 'happy': '😊', | |
| 'sad': '😢', | |
| 'angry': '😠', | |
| 'fearful': '😨', | |
| 'disgusted': '🤢', | |
| 'surprised': '😲', | |
| 'neutral': '😐' | |
| }; | |
| // Positive suggestions for each emotion | |
| const positiveSuggestions = { | |
| 'happy': "Your smile is contagious! Why not spread that joy by complimenting someone today?", | |
| 'sad': "It's okay to feel down sometimes. Try listening to your favorite music or calling a friend - you're not alone.", | |
| 'angry': "Take a deep breath. Try counting to 10 slowly. Remember, this feeling will pass.", | |
| 'fearful': "You're stronger than you think. Focus on what you can control right now.", | |
| 'disgusted': "Sometimes things bother us. Try shifting your focus to something beautiful around you.", | |
| 'surprised': "Life is full of surprises! Embrace the unexpected - it might lead to something wonderful.", | |
| 'neutral': "A calm moment is a gift. Enjoy this peaceful state or try something creative!" | |
| }; | |
| // Fun facts about emotions | |
| const emotionFacts = { | |
| 'happy': "Smiling (even when you don't feel like it) can actually trick your brain into feeling happier!", | |
| 'sad': "Tears contain stress hormones - crying literally helps your body release stress.", | |
| 'angry': "Anger typically lasts just 90 seconds if you don't feed it with more negative thoughts.", | |
| 'fearful': "Facing your fears in small doses can actually rewire your brain to be less afraid over time.", | |
| 'disgusted': "Disgust evolved to protect us from potential contaminants - your brain is looking out for you!", | |
| 'surprised': "Surprise helps us reset our attention and focus on new information more effectively.", | |
| 'neutral': "Neutral expressions are actually perceived as slightly positive by most people." | |
| }; | |
| // Initialize camera | |
| async function initCamera() { | |
| try { | |
| const stream = await navigator.mediaDevices.getUserMedia({ video: true }); | |
| video.srcObject = stream; | |
| // Load required face-api.js models | |
| await faceapi.nets.tinyFaceDetector.loadFromUri('https://justadudewhohacks.github.io/face-api.js/models'); | |
| await faceapi.nets.faceExpressionNet.loadFromUri('https://justadudewhohacks.github.io/face-api.js/models'); | |
| // Start face detection | |
| detectFaces(); | |
| } catch (err) { | |
| console.error("Error accessing camera:", err); | |
| alert("Could not access the camera. Please make sure you've granted camera permissions."); | |
| } | |
| } | |
| // Detect faces and emotions in real-time | |
| function detectFaces() { | |
| const displaySize = { width: video.width, height: video.height }; | |
| faceapi.matchDimensions(canvas, displaySize); | |
| setInterval(async () => { | |
| const detections = await faceapi.detectAllFaces(video, | |
| new faceapi.TinyFaceDetectorOptions()).withFaceExpressions(); | |
| // Clear canvas | |
| canvas.getContext('2d').clearRect(0, 0, canvas.width, canvas.height); | |
| if (detections.length > 0) { | |
| // Get the dominant emotion | |
| const expressions = detections[0].expressions; | |
| let dominantEmotion = 'neutral'; | |
| let maxConfidence = 0; | |
| for (const [emotion, confidence] of Object.entries(expressions)) { | |
| if (confidence > maxConfidence) { | |
| maxConfidence = confidence; | |
| dominantEmotion = emotion; | |
| } | |
| } | |
| // Update UI with results | |
| emojiDisplay.textContent = emotionEmojis[dominantEmotion]; | |
| emojiDisplay.classList.add('pulse'); | |
| createFallingSmileys(dominantEmotion); | |
| emotionText.textContent = `${dominantEmotion.charAt(0).toUpperCase() + dominantEmotion.slice(1)}`; | |
| confidenceText.textContent = `Confidence: ${Math.round(maxConfidence * 100)}%`; | |
| suggestionText.textContent = positiveSuggestions[dominantEmotion]; | |
| factText.textContent = emotionFacts[dominantEmotion]; | |
| } | |
| }, 2000); // Update every 4 seconds | |
| } | |
| // Set video dimensions when metadata is loaded | |
| video.addEventListener('loadedmetadata', () => { | |
| video.width = video.videoWidth; | |
| video.height = video.videoHeight; | |
| canvas.width = video.videoWidth; | |
| canvas.height = video.videoHeight; | |
| }); | |
| // Create falling smileys | |
| function createFallingSmileys(emotion) { | |
| const emoji = emotionEmojis[emotion]; | |
| const duration = 8; // Slower falling | |
| // Create multiple smileys | |
| for (let i = 0; i < 15; i++) { | |
| const smiley = document.createElement('div'); | |
| smiley.className = 'falling-smiley'; | |
| smiley.textContent = emoji; | |
| // Random position across the whole screen width | |
| const left = Math.random() * window.innerWidth; | |
| smiley.style.left = `${left}px`; | |
| smiley.style.top = '-50px'; // Start above the viewport | |
| smiley.style.animationDuration = `${duration + Math.random() * 4}s`; // Varying speeds | |
| // Random size variation | |
| const size = 1 + Math.random(); | |
| smiley.style.fontSize = `${size}rem`; | |
| document.body.appendChild(smiley); | |
| // Remove smiley after animation completes | |
| setTimeout(() => { | |
| smiley.remove(); | |
| }, duration * 1000); | |
| } | |
| } | |
| // Initialize app when page loads | |
| window.addEventListener('DOMContentLoaded', initCamera); | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=manmohanai/emotiondetector" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |