Code
Code
css:
.emotion-container {
max-width: 1200px;
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
margin: 0 auto;
}
.detect_emotions-heading{
color: #006B5F;
text-align: center;
padding: 20px 0;
margin: 0;
border-bottom: 2px solid #006B5F;
margin-bottom: 30px;
}
#videoContainer {
width: 640px;
height: 480px;
border: 3px solid #006B5F;
border-radius: 10px;
overflow: hidden;
margin-bottom: 20px;
}
#videoFeed {
width: 100%;
height: 100%;
object-fit: cover;
}
#detectedEmotion {
font-size: 24px;
font-weight: bold;
margin-top: 20px;
color: #006B5F;
}
#popup {
display: none;
position: fixed;
top: 20px;
right: 20px;
padding: 15px;
background-color: #006B5F;
color: white;
border-radius: 5px;
z-index: 1000;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
transition: opacity 0.3s;
}
select_emotion.css:
.emotions-section {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.emotions-heading {
color: #006B5F;
text-align: center;
padding: 20px 0;
margin: 0;
border-bottom: 2px solid #006B5F;
margin-bottom: 30px;
}
.emotions-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
padding: 20px;
}
.emotion-card {
background: white;
border-radius: 10px;
padding: 15px;
text-align: center;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
cursor: pointer;
transition: transform 0.2s, box-shadow 0.2s;
}
.emotion-card:hover {
transform: translateY(-5px);
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
}
.emotion-icon {
width: 100px;
height: 100px;
margin-bottom: 10px;
transition: transform 0.3s ease;
}
.emotion-card:hover .emotion-icon {
transform: scale(1.1);
}
.emotion-card p {
color: #006D5B;
font-size: 18px;
font-weight: bold;
margin: 10px 0 0 0;
}
.emotion-icon {
width: 80px;
height: 80px;
}
.emotion-card p {
font-size: 16px;
}
}
/* Navigation */
.nav {
background-color: #ffffff;
padding: 28px;
}
.nav a {
color: #006B5F;
text-decoration: none;
margin-right: 40px;
font-weight: 700;
font-size: 15px;
}
/* Banner */
.banner {
background: linear-gradient(90deg, #006B5F 35%, #48C9B0 65%);
padding: 40px 20px;
position: relative;
overflow: visible;
border-radius: 20px;
margin-right: 28px;
margin-left:28px;
}
.banner h1 {
color: white;
font-family: 'Poppins',sans-serif;
font-size: 38px;
font-weight: 700;
margin: 0;
padding-left: 20px;
}
.banner-image {
position: absolute;
right: -40px;
top: 45%;
transform: translateY(-52%);
width: 350px;
height: auto;
/* Surahs Section */
.surahs-section {
padding: 20px;
max-width: 1200px;
margin: 0 auto;
}
.surahs-heading {
color: #006B5F;
text-align: center;
padding: 20px 0;
margin: 0;
border-bottom: 2px solid #006B5F;
margin-bottom: 30px;
}
.surahs-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 20px;
padding: 20px;
}
.surah-card {
background: white;
border-radius: 10px;
padding: 15px;
text-align: center;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
cursor: pointer;
transition: transform 0.2s, box-shadow 0.2s;
}
.surah-card:hover {
transform: translateY(-5px);
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
}
.surah-number {
background: #4DB6AC;
color: white;
width: 30px;
height: 30px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto 10px;
font-size: 14px;
font-weight: bold;
}
.surah-arabic {
color: #006B5F;
font-size: 24px;
margin: 5px 0;
font-weight: bold;
}
.surah-english {
color: #666;
font-size: 16px;
margin: 5px 0;
}
.surah-info {
color: #999;
font-size: 12px;
margin-top: 5px;
}
.revelation-place {
background: #E8F5E9;
color: #2E7D32;
font-size: 12px;
padding: 4px 8px;
border-radius: 12px;
display: inline-block;
margin-top: 8px;
}
/* Loading State */
.loading {
text-align: center;
padding: 40px;
color: #006B5F;
font-size: 18px;
grid-column: 1 / -1;
}
.error {
text-align: center;
padding: 40px;
color: #ff0000;
font-size: 16px;
grid-column: 1 / -1;
background: #fff0f0;
border-radius: 8px;
margin: 20px;
}
surah.css:
.surah-banner {
background: linear-gradient(90deg, #006B5F 35%, #48C9B0 65%);
padding: 40px 20px;
position: relative;
overflow: visible;
border-radius: 20px;
margin-right: 28px;
margin-left:28px;
}
.surah-title {
color: white;
font-family: 'Poppins',sans-serif;
font-size: 38px;
font-weight: 700;
margin: 0;
padding-left: 20px;
}
.surah-container {
max-width: 1000px;
margin: 40px auto;
padding: 0 20px;
}
.verses-container {
background: white;
border-radius: 15px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
padding: 30px;
}
.verse {
position: relative;
margin-bottom: 30px;
padding: 20px 20px 20px 50px;
border-bottom: 1px solid #e0e0e0;
}
.verse:last-child {
border-bottom: none;
margin-bottom: 0;
}
.arabic-text {
font-size: 32px;
line-height: 2;
text-align: right;
margin-bottom: 10px;
color: #006B5F;
font-family: "Traditional Arabic", "Amiri", serif;
}
.verse-number {
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 35px;
height: 35px;
background: #48C9B0;
color: white;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
font-weight: bold;
}
.verses-container {
padding: 20px;
}
.arabic-text {
font-size: 28px;
}
.verse {
padding: 15px 15px 15px 40px;
}
.verse-number {
width: 30px;
height: 30px;
font-size: 12px;
}
}
emotion.js:
// Store the last detected emotion
let lastEmotion = null;
script.js:
// API URL constant
const API_URL = 'https://api.quran.com/api/v4/chapters';
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
try {
const surahs = await fetchSurahs();
if (!Array.isArray(surahs)) {
throw new Error('Invalid surahs data received');
}
emotionCards.forEach(card => {
const img = card.querySelector('img');
card.addEventListener('mouseenter', () => {
// Switch to GIF on hover
img.src = img.dataset.gif;
});
card.addEventListener('mouseleave', () => {
// Switch back to static image when hover ends
img.src = img.dataset.static;
});
card.addEventListener('click', () => {
const emotion = card.dataset.emotion;
detect_emotion.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>EMOMIN QURAN</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
<link rel="stylesheet" href="{{ url_for('static',
filename='css/emotion.css') }}">
<link href="https://fonts.googleapis.com/css2?
family=Montserrat:wght@400;500;600&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?
family=Poppins:wght@400;500;600&display=swap" rel="stylesheet">
</head>
<body>
<nav class="nav">
<a href="{{ url_for('index') }}">HOME</a>
<a href="{{ url_for('detect_emotion') }}">DETECT EMOTION</a>
<a href="{{ url_for('select_emotion') }}">SELECT EMOTION</a>
</nav>
<div class="banner">
<h1>EMOMIN QURAN</h1>
<img class="banner-image" src="{{ url_for('static', filename='images/quran-
icon.png') }}" alt="Quran">
</div>
<div class="emotion-container">
<h2 class="detect_emotions-heading">Detecting Emotion...</h1>
<div id="videoContainer">
<img id="videoFeed" src="" alt="Video Feed">
</div>
<div id="detectedEmotion"></div>
<div id="popup"></div>
</div>
<div class="banner">
<h1>EMOMIN QURAN</h1>
<img class="banner-image" src="{{ url_for('static', filename='images/quran-
icon.png') }}" alt="Quran">
</div>
<div class="surahs-section">
<h2 class="surahs-heading">Surahs</h2>
<div id="surahsGrid" class="surahs-grid">
<!-- Surahs will be loaded here dynamically -->
</div>
</div>
<script src="{{ url_for('static', filename='js/script.js') }}"></script>
</body>
</html>
select_emotion.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>EMOMIN QURAN</title>
<link rel="stylesheet" href="{{ url_for('static',
filename='css/style.css') }}">
<link rel="stylesheet" href="{{ url_for('static',
filename='css/select_emotion.css') }}">
<link rel="stylesheet" href="{{ url_for('static',
filename='css/style.css') }}">
<link href="https://fonts.googleapis.com/css2?
family=Montserrat:wght@400;500;600&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?
family=Poppins:wght@400;500;600&display=swap" rel="stylesheet">
</head>
<body>
<nav class="nav">
<a href="{{ url_for('index') }}">HOME</a>
<a href="{{ url_for('detect_emotion') }}" id="detectEmotionBtn">DETECT
EMOTION</a>
<a href="{{ url_for('select_emotion') }}">SELECT EMOTION</a>
</nav>
<div class="banner">
<h1>EMOMIN QURAN</h1>
<img class="banner-image" src="{{ url_for('static', filename='images/quran-
icon.png') }}" alt="Quran">
</div>
<div class="emotions-section">
<h2 class="emotions-heading">EMOTIONS</h2>
<div class="emotions-grid">
<div class="emotion-card" data-emotion="happy">
<img src="{{ url_for('static', filename='images/happy.jpg') }}"
data-static="{{ url_for('static', filename='images/happy.jpg') }}" data-
gif="{{ url_for('static', filename='images/happy.gif') }}" alt="Happy"
class="emotion-icon">
<p>HAPPY</p>
</div>
<div class="emotion-card" data-emotion="sad">
<img src="{{ url_for('static', filename='images/sad.jpg') }}" data-
static="{{ url_for('static', filename='images/sad.jpg') }}" data-
gif="{{ url_for('static', filename='images/sad.gif') }}" alt="Sad" class="emotion-
icon">
<p>SAD</p>
</div>
<div class="emotion-card" data-emotion="angry">
<img src="{{ url_for('static', filename='images/angry.jpg') }}"
data-static="{{ url_for('static', filename='images/angry.jpg') }}" data-
gif="{{ url_for('static', filename='images/angry.gif') }}" alt="Angry"
class="emotion-icon">
<p>ANGRY</p>
</div>
<div class="emotion-card" data-emotion="disgust">
<img src="{{ url_for('static', filename='images/disgust.jpg') }}"
data-static="{{ url_for('static', filename='images/disgust.jpg') }}" data-
gif="{{ url_for('static', filename='images/disgust.gif') }}" alt="Disgust"
class="emotion-icon">
<p>DISGUST</p>
</div>
<div class="emotion-card" data-emotion="surprise">
<img src="{{ url_for('static', filename='images/surprise.jpg') }}"
data-static="{{ url_for('static', filename='images/surprise.jpg') }}" data-
gif="{{ url_for('static', filename='images/surprise.gif') }}" alt="Surprise"
class="emotion-icon">
<p>SURPRISE</p>
</div>
<div class="emotion-card" data-emotion="fear">
<img src="{{ url_for('static', filename='images/fear.jpg') }}"
data-static="{{ url_for('static', filename='images/fear.jpg') }}" data-
gif="{{ url_for('static', filename='images/fear.gif') }}" alt="Fear"
class="emotion-icon">
<p>FEAR</p>
</div>
<div class="emotion-card" data-emotion="neutral">
<img src="{{ url_for('static', filename='images/neutral.jpg') }}"
data-static="{{ url_for('static', filename='images/neutral.jpg') }}" data-
gif="{{ url_for('static', filename='images/neutral.gif') }}" alt="Neutral"
class="emotion-icon">
<p>NEUTRAL</p>
</div>
</div>
</div>
<div class="surah-container">
<div class="verses-container">
{% for verse in surah.arabic1 %}
<div class="verse">
<div class="arabic-text">{{ verse }}</div>
<div class="verse-number">{{ loop.index }}</div>
</div>
{% endfor %}
</div>
</div>
</body>
</html>
app.py:
from flask import Flask, render_template, Response, jsonify
import cv2
from emotion import get_emotion
import requests
app = Flask(__name__)
def generate_frames():
global last_detected_emotion
cap = cv2.VideoCapture(0)
while True:
success, frame = cap.read()
if not success:
break
else:
# Get the detected emotion for the current frame
emotion = get_emotion(frame)
if emotion:
last_detected_emotion = emotion
@app.route('/')
def index():
return render_template('index.html')
@app.route('/detect-emotion')
def detect_emotion():
return render_template('detect_emotion.html')
@app.route('/select-emotion')
def select_emotion():
return render_template('select_emotion.html')
@app.route('/surah/<int:surah_id>')
def show_surah(surah_id):
try:
# Fetch surah data from the API
response = requests.get(f'https://quranapi.pages.dev/api/{surah_id}.json')
response.raise_for_status() # Raise an exception for bad status codes
surah_data = response.json()
@app.route('/video_feed')
def video_feed():
return Response(generate_frames(), mimetype='multipart/x-mixed-replace;
boundary=frame')
@app.route('/get_emotion')
def get_current_emotion():
global last_detected_emotion
return jsonify({'emotion': last_detected_emotion})
if __name__ == '__main__':
app.run(debug=True)
emotion.py:
import cv2
from deepface import DeepFace
import time
import logging
import threading
import numpy as np
class EmotionDetector:
def __init__(self):
# Load the face detection cascade classifier
self.face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades +
'haarcascade_frontalface_default.xml')
self.confidence_threshold = 0.7
self.time_window = 3
self.emotion_votes = {}
self.last_detected_emotion = None
self.last_emotion_time = 0
self.lock = threading.Lock()
if len(faces) == 0:
return None
# Extract the region of interest (ROI) for the first detected face
x, y, w, h = faces[0]
face_roi = frame[y:y + h, x:x + w]
try:
# Analyze the emotion in the face ROI
result = DeepFace.analyze(face_roi, actions=['emotion'],
enforce_detection=False)
if isinstance(result, list):
result = result[0]
emotion = result['dominant_emotion']
confidence = result['emotion'][emotion]
except Exception as e:
logging.error(f"Error in emotion detection: {e}")
return None
# Initialize logging
logging.basicConfig(filename='emotion_detection.log', level=logging.INFO)
def get_emotion(frame):
# Wrapper function to get emotion from the global EmotionDetector instance
return emotion_detector.detect_emotion(frame)