Spaces:
Running
Running
import streamlit as st | |
import cv2 | |
from deepface import DeepFace | |
import numpy as np | |
from retinaface import RetinaFace | |
from PIL import Image | |
import random | |
import time | |
import json | |
import os | |
from functools import lru_cache | |
import pandas as pd | |
import plotly.express as px | |
import threading | |
import concurrent.futures | |
import tensorflow as tf | |
try: | |
import torch | |
TORCH_AVAILABLE = True | |
except ImportError: | |
TORCH_AVAILABLE = False | |
def check_gpu_availability(): | |
gpu_available = False | |
gpu_info = "" | |
tf_gpu = len(tf.config.list_physical_devices('GPU')) > 0 | |
torch_gpu = False | |
if TORCH_AVAILABLE: | |
torch_gpu = torch.cuda.is_available() | |
gpu_available = tf_gpu or torch_gpu | |
if gpu_available: | |
if tf_gpu: | |
gpu_info += f"TensorFlow GPU: {tf.config.list_physical_devices('GPU')}\n" | |
if torch_gpu: | |
gpu_info += f"PyTorch GPU: {torch.cuda.get_device_name(0)}\n" | |
return gpu_available, gpu_info | |
def configure_gpu(): | |
try: | |
gpus = tf.config.experimental.list_physical_devices('GPU') | |
if gpus: | |
for gpu in gpus: | |
tf.config.experimental.set_memory_growth(gpu, True) | |
st.sidebar.success("GPU configured for optimal performance") | |
except Exception as e: | |
st.sidebar.warning(f"Could not configure GPU: {e}") | |
class NumpyJSONEncoder(json.JSONEncoder): | |
def default(self, obj): | |
if isinstance(obj, np.integer): | |
return int(obj) | |
elif isinstance(obj, np.floating): | |
return float(obj) | |
elif isinstance(obj, np.ndarray): | |
return obj.tolist() | |
return super(NumpyJSONEncoder, self).default(obj) | |
def save_user_preferences(prefs): | |
try: | |
with open(USER_PREF_PATH, "w") as f: | |
json.dump(prefs, f, cls=NumpyJSONEncoder) | |
except Exception as e: | |
st.error(f"Failed to save preferences: {e}") | |
GPU_AVAILABLE, GPU_INFO = check_gpu_availability() | |
if GPU_AVAILABLE: | |
configure_gpu() | |
if 'model_cache' not in st.session_state: | |
st.session_state['model_cache'] = {} | |
def load_face_model(model_name, use_gpu=False): | |
if model_name in st.session_state['model_cache']: | |
return st.session_state['model_cache'][model_name] | |
if use_gpu and GPU_AVAILABLE: | |
if model_name == "VGG-Face": | |
pass | |
st.session_state['model_cache'][model_name] = model_name | |
return model_name | |
def preprocess_image(img_array): | |
height, width = img_array.shape[:2] | |
max_dimension = 640 | |
if max(height, width) > max_dimension: | |
scale = max_dimension / max(height, width) | |
new_height = int(height * scale) | |
new_width = int(width * scale) | |
img_array = cv2.resize(img_array, (new_width, new_height)) | |
gray = cv2.cvtColor(img_array, cv2.COLOR_RGB2GRAY) | |
equalized = cv2.equalizeHist(gray) | |
enhanced = cv2.cvtColor(equalized, cv2.COLOR_GRAY2RGB) | |
brightened = cv2.convertScaleAbs(img_array, alpha=1.5, beta=30) | |
return {"original": img_array, "enhanced": enhanced, "brightened": brightened} | |
def detect_faces_with_fallback(img_array): | |
faces = None | |
detection_method = "none" | |
preprocessed = preprocess_image(img_array) | |
try: | |
faces = RetinaFace.detect_faces(preprocessed["original"]) | |
if faces: | |
detection_method = "retinaface_original" | |
return faces, detection_method | |
except Exception: | |
pass | |
try: | |
faces = RetinaFace.detect_faces(preprocessed["enhanced"]) | |
if faces: | |
detection_method = "retinaface_enhanced" | |
return faces, detection_method | |
except Exception: | |
pass | |
try: | |
faces = RetinaFace.detect_faces(preprocessed["brightened"]) | |
if faces: | |
detection_method = "retinaface_brightened" | |
return faces, detection_method | |
except Exception: | |
pass | |
try: | |
face_cascade = cv2.CascadeClassifier( | |
cv2.data.haarcascades + "haarcascade_frontalface_default.xml" | |
) | |
gray = cv2.cvtColor(img_array, cv2.COLOR_RGB2GRAY) | |
opencv_faces = face_cascade.detectMultiScale(gray, 1.1, 4) | |
if len(opencv_faces) > 0: | |
faces = {} | |
for i, (x, y, w, h) in enumerate(opencv_faces): | |
faces[f"face_{i+1}"] = {"facial_area": (x, y, w, h), "score": 0.9} | |
detection_method = "opencv_haar" | |
return faces, detection_method | |
except Exception: | |
pass | |
try: | |
result = DeepFace.extract_faces( | |
img_path=img_array, | |
enforce_detection=False, | |
detector_backend="opencv", | |
align=True, | |
) | |
if result and len(result) > 0: | |
faces = {} | |
for i, face_data in enumerate(result): | |
facial_area = face_data.get("facial_area", {}) | |
x = facial_area.get("x", 0) | |
y = facial_area.get("y", 0) | |
w = facial_area.get("w", 0) | |
h = facial_area.get("h", 0) | |
faces[f"face_{i+1}"] = {"facial_area": (x, y, w, h), "score": 0.8} | |
detection_method = "deepface_detector" | |
return faces, detection_method | |
except Exception: | |
pass | |
if not faces: | |
try: | |
from deepface.detectors import MTCNN | |
detector = MTCNN() | |
dets = detector.detect_faces(img_array) | |
if len(dets) > 0: | |
faces = {} | |
detection_method = "mtcnn_fallback" | |
for i, d in enumerate(dets): | |
x, y, w, h = d["box"] | |
faces[f"face_{i+1}"] = { | |
"facial_area": (x, y, w, h), | |
"score": d.get("confidence", 0.8), | |
} | |
return faces, detection_method | |
except Exception: | |
pass | |
return None, detection_method | |
def analyze_with_models(img_array): | |
results = [] | |
models_to_try = ["VGG-Face", "Facenet", "DeepID"] if GPU_AVAILABLE else ["VGG-Face", "Facenet"] | |
analyze_kwargs = { | |
"actions": ["emotion"], | |
"enforce_detection": False, | |
"detector_backend": "skip", | |
"prog_bar": False | |
} | |
if GPU_AVAILABLE: | |
analyze_kwargs["use_gpu"] = True | |
for model in models_to_try: | |
try: | |
model_obj = load_face_model(model, use_gpu=GPU_AVAILABLE) | |
result = DeepFace.analyze( | |
img_path=img_array, | |
**analyze_kwargs | |
) | |
if isinstance(result, list): | |
result = result[0] | |
if "emotion" in result: | |
for key in result["emotion"]: | |
if isinstance(result["emotion"][key], (np.floating, np.integer)): | |
result["emotion"][key] = float(result["emotion"][key]) | |
results.append(result) | |
if len(results) >= 2: | |
break | |
except Exception as e: | |
pass | |
return results | |
def weighted_average_results(results): | |
if not results: | |
return None | |
avg_result = results[0].copy() | |
weights = [1.0] * len(results) | |
for i, res in enumerate(results[1:], start=1): | |
if "emotion" in res and "emotion" in avg_result: | |
for key in avg_result["emotion"]: | |
if key in res["emotion"]: | |
avg_result["emotion"][key] += float(res["emotion"][key]) * weights[i] | |
total_weight = sum(weights) | |
if "emotion" in avg_result: | |
for key in avg_result["emotion"]: | |
avg_result["emotion"][key] = float(avg_result["emotion"][key]) / total_weight | |
dominant_key = max(avg_result["emotion"], key=avg_result["emotion"].get) | |
avg_result["dominant_emotion"] = dominant_key | |
return avg_result | |
def analyze_emotion_with_models(img_array): | |
max_dimension = 320 | |
height, width = img_array.shape[:2] | |
if max(height, width) > max_dimension: | |
scale = max_dimension / max(height, width) | |
small_img = cv2.resize(img_array, (int(width * scale), int(height * scale))) | |
else: | |
small_img = img_array.copy() | |
faces, detection_method = detect_faces_with_fallback(small_img) | |
if not faces: | |
return ( | |
None, | |
0, | |
"No face was detected. Please use better lighting or adjust your face position.", | |
) | |
try: | |
if isinstance(faces, dict) and len(faces) > 0: | |
face_key = list(faces.keys())[0] | |
face = faces[face_key] | |
x, y, w, h = face["facial_area"] | |
if max(height, width) > max_dimension: | |
scale_factor = max(height, width) / max_dimension | |
x = int(x * scale_factor) | |
y = int(y * scale_factor) | |
w = int(w * scale_factor) | |
h = int(h * scale_factor) | |
x, y = max(0, x), max(0, y) | |
w = min(w, img_array.shape[1] - x) | |
h = min(h, img_array.shape[0] - y) | |
if w > 0 and h > 0: | |
face_img = img_array[y:y+h, x:x+w] | |
else: | |
face_img = img_array | |
else: | |
face_img = img_array | |
results = analyze_with_models(face_img) | |
if not results: | |
return ( | |
None, | |
0, | |
"A face was detected, but we couldn't analyze the emotion. Please try a different angle or change your expression.", | |
) | |
result_dict = weighted_average_results(results) | |
if not result_dict or "emotion" not in result_dict: | |
return ( | |
None, | |
0, | |
"We found your face, but couldn't process the emotion data. Please try again with better lighting.", | |
) | |
dominant_emotion = result_dict["dominant_emotion"] | |
confidence = result_dict["emotion"][dominant_emotion] * 100 | |
confidence = float(confidence) | |
if confidence < 35: | |
return ( | |
None, | |
confidence, | |
"We found your face, but the confidence was too low to determine your mood. Please try a different angle or select your mood manually." | |
) | |
emotion_results = { | |
"emotions": {k: float(v) for k, v in result_dict["emotion"].items()}, | |
"dominant_emotion": dominant_emotion | |
} | |
return emotion_results, confidence, detection_method | |
except Exception as e: | |
st.error(f"Error in emotion analysis: {str(e)}") | |
return ( | |
None, | |
0, | |
"An error occurred during emotion analysis. Please try again." | |
) | |
st.set_page_config( | |
page_title="Music Recommendation System", | |
page_icon="πΌ", | |
layout="wide", | |
initial_sidebar_state="expanded", | |
) | |
USER_PREF_PATH = os.path.join(os.path.dirname(__file__), "user_preferences.json") | |
hindi_music_recommendations = { | |
"happy": [ | |
{ | |
"title": "Badtameez Dil β Yeh Jawaani Hai Deewani", | |
"url": "https://www.youtube.com/watch?v=II2EO3Nw4m0", | |
}, | |
{ | |
"title": "Gallan Goodiyaan β Dil Dhadakne Do", | |
"url": "https://www.youtube.com/watch?v=jCEdTq3j-0U", | |
}, | |
{ | |
"title": "Nagada Sang Dhol β Goliyon Ki Raasleela Ram-Leela", | |
"url": "https://www.youtube.com/watch?v=3X7x4Ye-tqo", | |
}, | |
{ | |
"title": "London Thumakda β Queen", | |
"url": "https://www.youtube.com/watch?v=udra3Mfw2oo", | |
}, | |
{ | |
"title": "Balam Pichkari β Yeh Jawaani Hai Deewani", | |
"url": "https://www.youtube.com/watch?v=0WtRNGubWGA", | |
}, | |
{ | |
"title": "Tune Maari Entriyaan β Gunday", | |
"url": "https://www.youtube.com/watch?v=2I3NgxDAiqE", | |
}, | |
{ | |
"title": "Kar Gayi Chull β Kapoor & Sons", | |
"url": "https://www.youtube.com/watch?v=NTHz9ephYTw", | |
}, | |
{ | |
"title": "Ghungroo β War", | |
"url": "https://www.youtube.com/watch?v=qFkNATtc3mc", | |
}, | |
{ | |
"title": "Aankh Marey β Simmba", | |
"url": "https://www.youtube.com/watch?v=O6OI2-p-gC4", | |
}, | |
{ | |
"title": "Morni Banke β Badhaai Ho", | |
"url": "https://www.youtube.com/watch?v=h-v5tHtL_cA", | |
}, | |
{ | |
"title": "Dil Dhadakne Do β Title Track", | |
"url": "https://www.youtube.com/watch?v=R5jQ8VudZbA", | |
}, | |
{ | |
"title": "Nashe Si Chadh Gayi β Befikre", | |
"url": "https://www.youtube.com/watch?v=Wd2B8OAOc9c", | |
}, | |
{ | |
"title": "Tamma Tamma Again β Badrinath Ki Dulhania", | |
"url": "https://www.youtube.com/watch?v=EEX_XM6SxmY", | |
}, | |
{ | |
"title": "Proper Patola β Namaste England", | |
"url": "https://www.youtube.com/watch?v=Y1O_aIV1FNM", | |
}, | |
{ | |
"title": "Abhi Toh Party Shuru Hui Hai β Khoobsurat", | |
"url": "https://www.youtube.com/watch?v=8LZgzAZ2lpQ", | |
}, | |
], | |
"sad": [ | |
{ | |
"title": "Channa Mereya β Ae Dil Hai Mushkil", | |
"url": "https://www.youtube.com/watch?v=284Ov7ysmfA", | |
}, | |
{ | |
"title": "Tum Hi Ho β Aashiqui 2", | |
"url": "https://www.youtube.com/watch?v=Umqb9KENgmk", | |
}, | |
{ | |
"title": "Luka Chuppi β Rang De Basanti", | |
"url": "https://www.youtube.com/watch?v=_ikZtcgAMxo", | |
}, | |
{ | |
"title": "Agar Tum Saath Ho β Tamasha", | |
"url": "https://www.youtube.com/watch?v=sK7riqg2mr4", | |
}, | |
{ | |
"title": "Judaai β Badlapur", | |
"url": "https://www.youtube.com/watch?v=zPpNZFgSzDo", | |
}, | |
{ | |
"title": "Kabhi Alvida Naa Kehna β KANK", | |
"url": "https://www.youtube.com/watch?v=O8fIwHfZz2E", | |
}, | |
{ | |
"title": "Main Dhoondne Ko Zamaane Mein β Heartless", | |
"url": "https://www.youtube.com/watch?v=5wqoxs9zG3w", | |
}, | |
{ | |
"title": "Tujhe Bhula Diya β Anjaana Anjaani", | |
"url": "https://www.youtube.com/watch?v=_SK9K58Olqo", | |
}, | |
{ | |
"title": "Phir Le Aaya Dil β Barfi!", | |
"url": "https://www.youtube.com/watch?v=ntC3sO-VeJY", | |
}, | |
{ | |
"title": "Bhula Dena β Aashiqui 2", | |
"url": "https://www.youtube.com/watch?v=j4OVQJ6-R1U", | |
}, | |
{ | |
"title": "Kabira (Encore) β Yeh Jawaani Hai Deewani", | |
"url": "https://www.youtube.com/watch?v=jHNNMj5bNQw", | |
}, | |
{ | |
"title": "Tera Ban Jaunga β Kabir Singh", | |
"url": "https://www.youtube.com/watch?v=mQiiw7uRngA", | |
}, | |
{ | |
"title": "Humsafar β Badrinath Ki Dulhania", | |
"url": "https://www.youtube.com/watch?v=8v-TWxPWIWc", | |
}, | |
{ | |
"title": "Agar Tum Mil Jao β Zeher", | |
"url": "https://www.youtube.com/watch?v=C8tMQzcPXOY", | |
}, | |
{ | |
"title": "Dil Ke Paas β Wajah Tum Ho", | |
"url": "https://www.youtube.com/watch?v=FOLUdLQBPuE", | |
}, | |
], | |
"angry": [ | |
{ | |
"title": "Challa β Jab Tak Hai Jaan", | |
"url": "https://www.youtube.com/watch?v=9a4izd3Rvdw", | |
}, | |
{ | |
"title": "Brothers Anthem β Brothers", | |
"url": "https://www.youtube.com/watch?v=IjBAgWKW12Y", | |
}, | |
{ | |
"title": "Sultan β Sultan", | |
"url": "https://www.youtube.com/watch?v=RYvUMglNznM", | |
}, | |
{ | |
"title": "Bulleya β Ae Dil Hai Mushkil", | |
"url": "https://www.youtube.com/watch?v=hXh35CtnSyU", | |
}, | |
{ | |
"title": "Sadda Haq β Rockstar", | |
"url": "https://www.youtube.com/watch?v=p9DQINKZxWE", | |
}, | |
{ | |
"title": "Jee Karda β Badlapur", | |
"url": "https://www.youtube.com/watch?v=BN45QQ7R92M", | |
}, | |
{ | |
"title": "Dhan Te Nan β Kaminey", | |
"url": "https://www.youtube.com/watch?v=m9RdKcnUvFU", | |
}, | |
{ | |
"title": "Bhaag DK Bose β Delhi Belly", | |
"url": "https://www.youtube.com/watch?v=IQEDu8SPHao", | |
}, | |
{ | |
"title": "Sher Aaya Sher β Gully Boy", | |
"url": "https://www.youtube.com/watch?v=hejXc_FSYb8", | |
}, | |
{ | |
"title": "Aala Re Aala β Simmba", | |
"url": "https://www.youtube.com/watch?v=2wbVxHlOepM", | |
}, | |
{ | |
"title": "Zinda β Bhaag Milkha Bhaag", | |
"url": "https://www.youtube.com/watch?v=RLzC55ai0eo", | |
}, | |
{ | |
"title": "Mardaani β Mardaani", | |
"url": "https://www.youtube.com/watch?v=C1QOVnH0bKY", | |
}, | |
{ | |
"title": "Jai Ho β Slumdog Millionaire", | |
"url": "https://www.youtube.com/watch?v=Yc5OyXmHD0w", | |
}, | |
{ | |
"title": "Malhari β Bajirao Mastani", | |
"url": "https://www.youtube.com/watch?v=l_MyUGq7pgs", | |
}, | |
{ | |
"title": "Apna Time Aayega β Gully Boy", | |
"url": "https://www.youtube.com/watch?v=SlHnlxDt2TQ", | |
}, | |
], | |
"fear": [ | |
{ | |
"title": "Darr Ke Aage Jeet Hai β Mountain Dew", | |
"url": "https://www.youtube.com/watch?v=xT7E-n1t3vI", | |
}, | |
{ | |
"title": "Hai Ram β Sarkar Raj", | |
"url": "https://www.youtube.com/watch?v=zDQUylzavMQ", | |
}, | |
{ | |
"title": "Aaj Phir Jeene Ki Tamanna Hai β Guide", | |
"url": "https://www.youtube.com/watch?v=2LG8LwEVlJE", | |
}, | |
{ | |
"title": "Main Hoon Don β Don", | |
"url": "https://www.youtube.com/watch?v=xvNgjtgXOVo", | |
}, | |
{ | |
"title": "Khalbali β Rang De Basanti", | |
"url": "https://www.youtube.com/watch?v=Yd-ngSyDZss", | |
}, | |
{ | |
"title": "Bhoot Hoon Main β Bhoot", | |
"url": "https://www.youtube.com/watch?v=JNV4To5uzKA", | |
}, | |
{ | |
"title": "Bhool Bhulaiyaa β Title Track", | |
"url": "https://www.youtube.com/watch?v=eN6AYHAT8UM", | |
}, | |
{ | |
"title": "Darr β Title Track", | |
"url": "https://www.youtube.com/watch?v=BTAXAc1bJh8", | |
}, | |
{ | |
"title": "Pari β Title Track", | |
"url": "https://www.youtube.com/watch?v=ZwyKOXwJsC0", | |
}, | |
{ | |
"title": "Bol Na Halke Halke β Jhoom Barabar Jhoom", | |
"url": "https://www.youtube.com/watch?v=S9LZjGGeedw", | |
}, | |
{ | |
"title": "Raat Ka Nasha β Asoka", | |
"url": "https://www.youtube.com/watch?v=OjaFNUA-UFE", | |
}, | |
{ | |
"title": "Phir Se Ud Chala β Rockstar", | |
"url": "https://www.youtube.com/watch?v=2mWaqsC3U7k", | |
}, | |
{ | |
"title": "Roobaroo β Rang De Basanti", | |
"url": "https://www.youtube.com/watch?v=BrfRB6aTZlM", | |
}, | |
{ | |
"title": "Khamoshiyan β Khamoshiyan", | |
"url": "https://www.youtube.com/watch?v=FXiaIH49oAU", | |
}, | |
{ | |
"title": "Tum Ho Toh β Rock On!!", | |
"url": "https://www.youtube.com/watch?v=hCsY8T0uBGA", | |
}, | |
], | |
"neutral": [ | |
{ | |
"title": "Kabira β Yeh Jawaani Hai Deewani", | |
"url": "https://www.youtube.com/watch?v=jHNNMj5bNQw", | |
}, | |
{ | |
"title": "Mitwa β Kabhi Alvida Naa Kehna", | |
"url": "https://www.youtube.com/watch?v=Cv86br9MSBc", | |
}, | |
{ | |
"title": "Kun Faya Kun β Rockstar", | |
"url": "https://www.youtube.com/watch?v=T94PHkuydcw", | |
}, | |
{ | |
"title": "Tum Se Hi β Jab We Met", | |
"url": "https://www.youtube.com/watch?v=mt9xg0mmt28", | |
}, | |
{ | |
"title": "Iktara β Wake Up Sid", | |
"url": "https://www.youtube.com/watch?v=fSS_R91Nimw", | |
}, | |
{ | |
"title": "Nazm Nazm β Bareilly Ki Barfi", | |
"url": "https://www.youtube.com/watch?v=DK_UsATwoxI", | |
}, | |
{ | |
"title": "Ae Dil Hai Mushkil β ADHM", | |
"url": "https://www.youtube.com/watch?v=6FURuLYrR_Q", | |
}, | |
{ | |
"title": "Raabta β Agent Vinod", | |
"url": "https://www.youtube.com/watch?v=zAU_rsoS5ok", | |
}, | |
{ | |
"title": "Tera Hone Laga Hoon β Ajab Prem Ki Ghazab Kahani", | |
"url": "https://www.youtube.com/watch?v=K0IvuwrSFaI", | |
}, | |
{ | |
"title": "Safarnama β Tamasha", | |
"url": "https://www.youtube.com/watch?v=zLv0V_19L-A", | |
}, | |
{ | |
"title": "Pehli Nazar Mein β Race", | |
"url": "https://www.youtube.com/watch?v=BadBAMnPX0I", | |
}, | |
{ | |
"title": "Saibo β Shor in the City", | |
"url": "https://www.youtube.com/watch?v=zXLgYBSdv74", | |
}, | |
{ | |
"title": "O Re Piya β Aaja Nachle", | |
"url": "https://www.youtube.com/watch?v=iv7lcUkFVSc", | |
}, | |
{ | |
"title": "Khairiyat β Chhichhore", | |
"url": "https://www.youtube.com/watch?v=hoNb6HuNmU0", | |
}, | |
{ | |
"title": "Manwa Laage β Happy New Year", | |
"url": "https://www.youtube.com/watch?v=d8IT-16kA8M", | |
}, | |
], | |
"disgust": [ | |
{ | |
"title": "Beedi β Omkara", | |
"url": "https://www.youtube.com/watch?v=XLJCtZKQGrY", | |
}, | |
{ | |
"title": "Emotional Atyachaar β Dev D", | |
"url": "https://www.youtube.com/watch?v=Vng5mg0iY0k", | |
}, | |
{ | |
"title": "Gandi Baat β R... Rajkumar", | |
"url": "https://www.youtube.com/watch?v=vvLBXO4MnKQ", | |
}, | |
{ | |
"title": "Bluffmaster β Bluffmaster", | |
"url": "https://www.youtube.com/watch?v=t5UzO4gOYKc", | |
}, | |
{ | |
"title": "Dhoom Machale β Dhoom", | |
"url": "https://www.youtube.com/watch?v=ymk2_5a2V8g", | |
}, | |
{ | |
"title": "Zor Ka Jhatka β Action Replayy", | |
"url": "https://www.youtube.com/watch?v=UZV8Yb4hVgU", | |
}, | |
{ | |
"title": "Genda Phool β Delhi-6", | |
"url": "https://www.youtube.com/watch?v=f0CvPQ3l-Xg", | |
}, | |
{ | |
"title": "Dum Maro Dum β Hare Rama Hare Krishna", | |
"url": "https://www.youtube.com/watch?v=BZNT_Y-mAkE", | |
}, | |
{ | |
"title": "Chaar Botal Vodka β Ragini MMS 2", | |
"url": "https://www.youtube.com/watch?v=x8F5dz8kv1w", | |
}, | |
{ | |
"title": "Kamli β Dhoom 3", | |
"url": "https://www.youtube.com/watch?v=C8kSrkz8Hz8", | |
}, | |
{ | |
"title": "Munni Badnaam Hui β Dabangg", | |
"url": "https://www.youtube.com/watch?v=Jn5hsfbhWx4", | |
}, | |
{ | |
"title": "Sheila Ki Jawani β Tees Maar Khan", | |
"url": "https://www.youtube.com/watch?v=ZTmF2v59CtI", | |
}, | |
{ | |
"title": "Baby Doll β Ragini MMS 2", | |
"url": "https://www.youtube.com/watch?v=yP9KiFTyBks", | |
}, | |
{ | |
"title": "Oo Antava β Pushpa", | |
"url": "https://www.youtube.com/watch?v=kyNdRJR_NRs", | |
}, | |
{ | |
"title": "Laila Main Laila β Raees", | |
"url": "https://www.youtube.com/watch?v=fMW7ze7-Gik", | |
}, | |
], | |
"surprise": [ | |
{ | |
"title": "Kala Chashma β Baar Baar Dekho", | |
"url": "https://www.youtube.com/watch?v=k4yXQkG2s1E", | |
}, | |
{ | |
"title": "Matargashti β Tamasha", | |
"url": "https://www.youtube.com/watch?v=6vKucgAeF_Q", | |
}, | |
{ | |
"title": "Sooraj Dooba Hain β Roy", | |
"url": "https://www.youtube.com/watch?v=nJZcbidTutE", | |
}, | |
{ | |
"title": "Ghagra β Yeh Jawaani Hai Deewani", | |
"url": "https://www.youtube.com/watch?v=caoGNx1LF2Q", | |
}, | |
{ | |
"title": "Ishq Shava β Jab Tak Hai Jaan", | |
"url": "https://www.youtube.com/watch?v=2kH4fLrwc0A", | |
}, | |
{ | |
"title": "Naina β Dangal", | |
"url": "https://www.youtube.com/watch?v=BTtx6HMzunQ", | |
}, | |
{ | |
"title": "Haanikaarak Bapu β Dangal", | |
"url": "https://www.youtube.com/watch?v=KyZZrClK0rM", | |
}, | |
{ | |
"title": "Malhari β Bajirao Mastani", | |
"url": "https://www.youtube.com/watch?v=l_MyUGq7pgs", | |
}, | |
{ | |
"title": "Dilbar β Satyameva Jayate", | |
"url": "https://www.youtube.com/watch?v=JFcgOboQZ08", | |
}, | |
{ | |
"title": "Bom Diggy Diggy β Sonu Ke Titu Ki Sweety", | |
"url": "https://www.youtube.com/watch?v=yIIGQB6EMAM", | |
}, | |
{ | |
"title": "Cutiepie β Ae Dil Hai Mushkil", | |
"url": "https://www.youtube.com/watch?v=f6vY6tYvKGA", | |
}, | |
{ | |
"title": "Coca Cola β Luka Chuppi", | |
"url": "https://www.youtube.com/watch?v=_cPHiwPqbqo", | |
}, | |
{ | |
"title": "Sweety Tera Drama β Bareilly Ki Barfi", | |
"url": "https://www.youtube.com/watch?v=1MU4wjcxoR4", | |
}, | |
{ | |
"title": "Dil Chori β Sonu Ke Titu Ki Sweety", | |
"url": "https://www.youtube.com/watch?v=MU9oULiwmaU", | |
}, | |
{ | |
"title": "Koi Kahe Kehta Rahe β Dil Chahta Hai", | |
"url": "https://www.youtube.com/watch?v=4vEBkbkzwR8", | |
}, | |
], | |
} | |
def load_css(): | |
st.markdown( | |
""" | |
<style> | |
* { | |
font-family: 'Segoe UI', Arial, sans-serif !important; | |
} | |
.main-header { | |
font-size: 2.8rem; | |
color: #ff5722; | |
text-align: center; | |
margin-bottom: 1.5rem; | |
font-weight: bold; | |
text-shadow: 2px 2px 4px rgba(0,0,0,0.1); | |
background: linear-gradient(45deg, #ff5722, #FF9800); | |
-webkit-background-clip: text; | |
-webkit-text-fill-color: transparent; | |
// animation: pulse 2s infinite; | |
} | |
@keyframes pulse { | |
0% { transform: scale(1); } | |
50% { transform: scale(1.03); } | |
100% { transform: scale(1); } | |
} | |
.hindi-title { | |
font-size: 1.5rem; | |
color: #333; | |
font-weight: 600; | |
margin-bottom: 0.5rem; | |
} | |
.subheader { | |
font-size: 1.8rem; | |
color: #ff5722; | |
margin-bottom: 1rem; | |
text-transform: uppercase; | |
letter-spacing: 1px; | |
border-bottom: 2px solid #ff5722; | |
padding-bottom: 0.5rem; | |
} | |
.emotion-card { | |
padding: 1.5rem; | |
border-radius: 12px; | |
margin-bottom: 1.5rem; | |
background-color: #2596be; | |
border-left: 5px solid #ff5722; | |
box-shadow: 0 4px 6px rgba(0,0,0,0.05); | |
transition: all 0.3s ease; | |
} | |
.emotion-card:hover { | |
box-shadow: 0 6px 12px rgba(0,0,0,0.1); | |
transform: translateY(-3px); | |
} | |
.recommendation-card { | |
padding: 1.5rem; | |
border-radius: 12px; | |
margin: 1.5rem 0; | |
background-color: #009933; | |
border-left: 6px solid #ff5722; | |
box-shadow: 0 4px 15px rgba(0,0,0,0.08); | |
transition: transform 0.3s; | |
} | |
.recommendation-card:hover { | |
transform: translateY(-5px); | |
box-shadow: 0 8px 20px rgba(0,0,0,0.12); | |
} | |
.stButton>button { | |
background-color: #ff5722; | |
color: white; | |
border-radius: 20px; | |
font-size: 1rem; | |
padding: 0.5rem 1.5rem; | |
border: none; | |
box-shadow: 0 2px 5px rgba(0,0,0,0.1); | |
transition: all 0.3s; | |
} | |
.stButton>button:hover { | |
background-color: #ffffff; | |
box-shadow: 0 4px 8px rgba(0,0,0,0.15); | |
transform: translateY(-2px); | |
} | |
.like-button { | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
} | |
.mood-button { | |
text-align: center; | |
margin-bottom: 12px; | |
} | |
.mood-emoji { | |
font-size: 2.2rem; | |
margin-bottom: 8px; | |
display: block; | |
} | |
.mood-label { | |
display: block; | |
text-align: center; | |
} | |
.stSelectbox>div>div { | |
background-color: #06c91a; | |
border: 1px solid #ddd; | |
border-radius: 8px; | |
} | |
.info-box { | |
background-color: #009933; | |
border-left: 4px solid #2196F3; | |
padding: 1rem; | |
border-radius: 8px; | |
margin-bottom: 1rem; | |
} | |
.feature-card { | |
background-color: #3399ff; | |
border-radius: 10px; | |
box-shadow: 0 4px 6px rgba(0,0,0,0.05); | |
padding: 1.5rem; | |
margin-bottom: 1rem; | |
transition: all 0.3s ease; | |
border-top: 4px solid #ff5722; | |
} | |
.feature-card:hover { | |
transform: translateY(-5px); | |
box-shadow: 0 8px 15px rgba(0,0,0,0.1); | |
} | |
.feature-icon { | |
font-size: 2rem; | |
margin-bottom: 0.5rem; | |
color: #ff5722; | |
} | |
.sidebar-info { | |
background-color: #ffffff; | |
padding: 1rem; | |
border-radius: 8px; | |
margin-top: 1rem; | |
} | |
.sidebar-header { | |
color: #ff5722; | |
font-size: 1.2rem; | |
font-weight: bold; | |
margin-bottom: 0.5rem; | |
} | |
.step-container { | |
display: flex; | |
margin-bottom: 1rem; | |
} | |
.step-number { | |
background-color: #ff5722; | |
color: white; | |
width: 30px; | |
height: 30px; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
border-radius: 50%; | |
margin-right: 10px; | |
flex-shrink: 0; | |
} | |
.step-content { | |
flex: 1; | |
} | |
.footer { | |
text-align: center; | |
margin-top: 3rem; | |
padding-top: 1rem; | |
border-top: 1px solid #eee; | |
font-size: 0.9rem; | |
color: #777; | |
} | |
@keyframes fadeIn { | |
from { opacity: 0; transform: translateY(20px); } | |
to { opacity: 1; transform: translateY(0); } | |
} | |
.animated-fade { | |
animation: fadeIn 0.5s ease-out; | |
} | |
.stVideo { | |
border-radius: 10px; | |
overflow: hidden; | |
box-shadow: 0 4px 8px rgba(0,0,0,0.1); | |
} | |
.hide-on-secondary-pages { | |
display: none; | |
} | |
.show-on-home { | |
display: block; | |
} | |
.custom-mood-btn { | |
width: 100%; | |
border-radius: 12px; | |
padding: 10px; | |
background-color: #ffffff; | |
color: #333; | |
border: 1px solid #ddd; | |
cursor: pointer; | |
display: flex; | |
flex-direction: column; | |
align-items: center; | |
justify-content: center; | |
transition: all 0.3s ease; | |
margin-bottom: 10px; | |
} | |
.custom-mood-btn:hover { | |
background-color: #ffffff; | |
transform: translateY(-3px); | |
box-shadow: 0 4px 8px rgba(0,0,0,0.1); | |
} | |
</style> | |
""", | |
unsafe_allow_html=True, | |
) | |
def load_user_preferences(): | |
if not os.path.exists(USER_PREF_PATH): | |
return {"liked_songs": [], "emotion_history": []} | |
try: | |
with open(USER_PREF_PATH, "r") as f: | |
return json.load(f) | |
except: | |
return {"liked_songs": [], "emotion_history": []} | |
def load_face_model(model_name): | |
return model_name | |
def preprocess_image(img_array): | |
gray = cv2.cvtColor(img_array, cv2.COLOR_RGB2GRAY) | |
equalized = cv2.equalizeHist(gray) | |
enhanced = cv2.cvtColor(equalized, cv2.COLOR_GRAY2RGB) | |
brightened = cv2.convertScaleAbs(img_array, alpha=1.5, beta=30) | |
return {"original": img_array, "enhanced": enhanced, "brightened": brightened} | |
def detect_faces_with_fallback(img_array): | |
faces = None | |
detection_method = "none" | |
preprocessed = preprocess_image(img_array) | |
try: | |
faces = RetinaFace.detect_faces(preprocessed["original"]) | |
if faces: | |
detection_method = "retinaface_original" | |
return faces, detection_method | |
except Exception: | |
pass | |
try: | |
faces = RetinaFace.detect_faces(preprocessed["enhanced"]) | |
if faces: | |
detection_method = "retinaface_enhanced" | |
return faces, detection_method | |
except Exception: | |
pass | |
try: | |
faces = RetinaFace.detect_faces(preprocessed["brightened"]) | |
if faces: | |
detection_method = "retinaface_brightened" | |
return faces, detection_method | |
except Exception: | |
pass | |
try: | |
face_cascade = cv2.CascadeClassifier( | |
cv2.data.haarcascades + "haarcascade_frontalface_default.xml" | |
) | |
gray = cv2.cvtColor(img_array, cv2.COLOR_RGB2GRAY) | |
opencv_faces = face_cascade.detectMultiScale(gray, 1.1, 4) | |
if len(opencv_faces) > 0: | |
faces = {} | |
for i, (x, y, w, h) in enumerate(opencv_faces): | |
faces[f"face_{i+1}"] = {"facial_area": (x, y, w, h), "score": 0.9} | |
detection_method = "opencv_haar" | |
return faces, detection_method | |
except Exception: | |
pass | |
try: | |
result = DeepFace.extract_faces( | |
img_path=img_array, | |
enforce_detection=False, | |
detector_backend="opencv", | |
align=True, | |
) | |
if result and len(result) > 0: | |
faces = {} | |
for i, face_data in enumerate(result): | |
facial_area = face_data.get("facial_area", {}) | |
x = facial_area.get("x", 0) | |
y = facial_area.get("y", 0) | |
w = facial_area.get("w", 0) | |
h = facial_area.get("h", 0) | |
faces[f"face_{i+1}"] = {"facial_area": (x, y, w, h), "score": 0.8} | |
detection_method = "deepface_detector" | |
return faces, detection_method | |
except Exception: | |
pass | |
if not faces: | |
try: | |
from deepface.detectors import MTCNN | |
detector = MTCNN() | |
dets = detector.detect_faces(img_array) | |
if len(dets) > 0: | |
faces = {} | |
detection_method = "mtcnn_fallback" | |
for i, d in enumerate(dets): | |
x, y, w, h = d["box"] | |
faces[f"face_{i+1}"] = { | |
"facial_area": (x, y, w, h), | |
"score": d.get("confidence", 0.8), | |
} | |
return faces, detection_method | |
except Exception: | |
pass | |
return None, detection_method | |
def analyze_with_models(img_array): | |
results = [] | |
models = ["VGG-Face", "Facenet", "OpenFace", "DeepID", "ArcFace", "Dlib"] | |
for model in models: | |
try: | |
result = DeepFace.analyze( | |
img_path=img_array, | |
actions=("age", "gender", "race", "emotion"), | |
enforce_detection=False, | |
detector_backend="retinaface", | |
) | |
if isinstance(result, list): | |
result = result[0] | |
results.append(result) | |
except Exception as e: | |
st.error(f"Error Analyzing With Model {model}: {str(e)}") | |
return results | |
def weighted_average_results(results): | |
if not results: | |
return None | |
avg_result = results[0].copy() | |
weights = [1.0] * len(results) | |
for i, res in enumerate(results[1:], start=1): | |
if "age" in res and "age" in avg_result: | |
avg_result["age"] += res["age"] * weights[i] | |
if "gender" in res and "gender" in avg_result: | |
if res["gender"] == "Woman": | |
avg_result["gender"] = "Woman" | |
if "race" in res and "race" in avg_result: | |
for key in avg_result["race"]: | |
if key in res["race"]: | |
avg_result["race"][key] += res["race"][key] * weights[i] | |
if "emotion" in res and "emotion" in avg_result: | |
for key in avg_result["emotion"]: | |
if key in res["emotion"]: | |
avg_result["emotion"][key] += res["emotion"][key] * weights[i] | |
total_weight = sum(weights) | |
if "age" in avg_result: | |
avg_result["age"] /= total_weight | |
if "race" in avg_result: | |
for key in avg_result["race"]: | |
avg_result["race"][key] /= total_weight | |
if "emotion" in avg_result: | |
for key in avg_result["emotion"]: | |
avg_result["emotion"][key] /= total_weight | |
avg_result["dominant_emotion"] = max(avg_result["emotion"], key=avg_result["emotion"].get) | |
return avg_result | |
def analyze_emotion_with_models(img_array): | |
faces, detection_method = detect_faces_with_fallback(img_array) | |
if not faces: | |
return ( | |
None, | |
0, | |
"No face was detected. Please use better lighting or adjust your face position.", | |
) | |
try: | |
if isinstance(faces, dict) and len(faces) > 0: | |
face_key = list(faces.keys())[0] | |
face = faces[face_key] | |
x, y, w, h = face["facial_area"] | |
x, y = max(0, x), max(0, y) | |
w = min(w, img_array.shape[1] - x) | |
h = min(h, img_array.shape[0] - y) | |
if w > 0 and h > 0: | |
face_img = img_array[y : y + h, x : x + w] | |
else: | |
face_img = img_array | |
else: | |
face_img = img_array | |
results = analyze_with_models(face_img) | |
if not results: | |
return ( | |
None, | |
0, | |
"A face was detected, but we couldn't analyze the emotion. Please try a different angle or change your expression.", | |
) | |
result_dict = weighted_average_results(results) | |
if not result_dict or "emotion" not in result_dict: | |
return ( | |
None, | |
0, | |
"We found your face, but couldn't process the emotion data. Please try again with better lighting.", | |
) | |
dominant_emotion = result_dict["dominant_emotion"] | |
confidence = result_dict["emotion"][dominant_emotion] * 100 | |
if confidence < 35: | |
return ( | |
None, | |
confidence, | |
"We found your face, but the confidence was too low to determine your mood. Please try a different angle or select your mood manually." | |
) | |
emotion_results = {"emotions": result_dict["emotion"], "dominant_emotion": dominant_emotion} | |
return emotion_results, confidence, detection_method | |
except Exception as e: | |
st.error(f"Error in emotion analysis: {str(e)}") | |
return ( | |
None, | |
0, | |
"An error occurred during emotion analysis. Please try again." | |
) | |
def music_recommendation(): | |
st.markdown( | |
'<p class="subheader">Music that matches your mood</p>', unsafe_allow_html=True | |
) | |
st.markdown( | |
'<div class="info-box">π <b>How it works:</b> Choose your mood below or take a photo so we can see how you feel. We will suggest songs that match your mood.</div>', | |
unsafe_allow_html=True, | |
) | |
user_prefs = load_user_preferences() | |
st.markdown("### Select Your Mood:") | |
st.markdown('<div class="animated-fade">', unsafe_allow_html=True) | |
st.write("Click on how you feel right now:") | |
all_moods = { | |
"happy": {"emoji": "π", "label": "Happy"}, | |
"sad": {"emoji": "π’", "label": "Sad"}, | |
"angry": {"emoji": "π ", "label": "Angry"}, | |
"fear": {"emoji": "π¨", "label": "Fear"}, | |
"neutral": {"emoji": "π", "label": "Neutral"}, | |
"disgust": {"emoji": "π€’", "label": "Disgust"}, | |
"surprise": {"emoji": "π²", "label": "Surprise"}, | |
} | |
mood_selected = None | |
cols_row1 = st.columns(4) | |
mood_keys = list(all_moods.keys()) | |
for i in range(4): | |
mood = mood_keys[i] | |
mood_info = all_moods[mood] | |
with cols_row1[i]: | |
st.markdown('<div class="mood-button">', unsafe_allow_html=True) | |
if st.button( | |
f"{mood_info['emoji']} {mood_info['label']}", key=f"mood_{mood}" | |
): | |
mood_selected = mood | |
st.markdown("</div>", unsafe_allow_html=True) | |
cols_row2 = st.columns(3) | |
for i in range(4, len(mood_keys)): | |
col_idx = i - 4 | |
mood = mood_keys[i] | |
mood_info = all_moods[mood] | |
with cols_row2[col_idx]: | |
st.markdown('<div class="mood-button">', unsafe_allow_html=True) | |
if st.button( | |
f"{mood_info['emoji']} {mood_info['label']}", key=f"mood_{mood}" | |
): | |
mood_selected = mood | |
st.markdown("</div>", unsafe_allow_html=True) | |
st.markdown("</div>", unsafe_allow_html=True) | |
st.markdown("<hr style='margin: 2rem 0; opacity: 0.3;'>", unsafe_allow_html=True) | |
st.markdown('<div class="animated-fade">', unsafe_allow_html=True) | |
st.markdown("### Or Take or Upload a Photo") | |
st.write("Let our AI check your face to see how you're feeling.") | |
col1, col2 = st.columns([1, 1]) | |
with col1: | |
use_camera = st.checkbox("Use Camera", value=False) | |
img_file = None | |
if use_camera: | |
img_file = st.camera_input("Take a photo", key="camera_input") | |
st.write("OR") | |
uploaded_file = st.file_uploader("Upload a photo", type=["jpg", "jpeg", "png"]) | |
with st.expander("π· Tips to help detect faces better:"): | |
st.markdown( | |
""" | |
- Make sure your face is well-lit | |
- Look directly at the camera | |
- Remove sunglasses or hats | |
- Keep your face in the center of the frame | |
- If your face isn't detected, try a different angle | |
""" | |
) | |
st.markdown("</div>", unsafe_allow_html=True) | |
if mood_selected: | |
timestamp = time.strftime("%Y-%m-%d %H:%M:%S") | |
user_prefs["emotion_history"].append( | |
{ | |
"emotion": mood_selected, | |
"confidence": 100.0, | |
"timestamp": timestamp, | |
"selection": "manual", | |
} | |
) | |
save_user_preferences(user_prefs) | |
st.markdown('<div class="animated-fade">', unsafe_allow_html=True) | |
st.markdown( | |
f'<div class="emotion-card"><h3>{all_moods[mood_selected]["emoji"]} Your Selected Mood</h3>' | |
f"<p>You're feeling: <strong>{mood_selected.capitalize()}</strong></p></div>", | |
unsafe_allow_html=True, | |
) | |
st.markdown("</div>", unsafe_allow_html=True) | |
show_hindi_recommendations(mood_selected, user_prefs) | |
image_source = img_file or uploaded_file | |
if image_source is not None: | |
with st.spinner("Our AI is checking your mood..."): | |
img = Image.open(image_source) | |
img_array = np.array(img) | |
progress_bar = st.progress(0) | |
progress_bar.progress(25) | |
emotion_results, confidence, detection_method = analyze_emotion_with_models( | |
img_array | |
) | |
progress_bar.progress(75) | |
with col2: | |
st.image(img, caption="Your photo", use_container_width=True) | |
if emotion_results: | |
if confidence > 25: | |
dominant_emotion = emotion_results["dominant_emotion"] | |
emotion_emojis = { | |
"happy": "π", | |
"sad": "π’", | |
"angry": "π ", | |
"fear": "π¨", | |
"neutral": "π", | |
"disgust": "π€’", | |
"surprise": "π²", | |
} | |
emoji = emotion_emojis.get(dominant_emotion, "") | |
st.markdown('<div class="animated-fade">', unsafe_allow_html=True) | |
st.markdown( | |
f'<div class="emotion-card"><h3>{emoji} Your mood check</h3>' | |
f"<p>We detected that you're feeling: <strong>{dominant_emotion.capitalize()}</strong> " | |
f"(Confidence: {confidence:.1f}%)</p></div>", | |
unsafe_allow_html=True, | |
) | |
emotions_df = pd.DataFrame( | |
{ | |
"Emotion": list(emotion_results["emotions"].keys()), | |
"Confidence": list(emotion_results["emotions"].values()), | |
} | |
) | |
fig = px.bar( | |
emotions_df, | |
x="Emotion", | |
y="Confidence", | |
color="Emotion", | |
title="Your emotion results.", | |
labels={ | |
"Confidence": "Confidence %", | |
"Emotion": "Emotions Detected", | |
}, | |
) | |
fig.update_layout( | |
plot_bgcolor="rgba(0,0,0,0)", | |
paper_bgcolor="rgba(0,0,0,0)", | |
font=dict(family="Segoe UI, Arial, sans-serif"), | |
) | |
st.plotly_chart(fig, use_container_width=True) | |
st.markdown("</div>", unsafe_allow_html=True) | |
progress_bar.progress(100) | |
timestamp = time.strftime("%Y-%m-%d %H:%M:%S") | |
user_prefs["emotion_history"].append( | |
{ | |
"emotion": dominant_emotion, | |
"confidence": confidence, | |
"timestamp": timestamp, | |
"selection": "ai", | |
} | |
) | |
if len(user_prefs["emotion_history"]) > 50: | |
user_prefs["emotion_history"] = user_prefs["emotion_history"][ | |
-50: | |
] | |
save_user_preferences(user_prefs) | |
show_hindi_recommendations(dominant_emotion, user_prefs) | |
else: | |
st.warning( | |
f"We found your face but the confidence ({confidence:.1f}%) " | |
"is too low to determine your mood. Please try again or select manually." | |
) | |
else: | |
if detection_method != "none": | |
st.warning( | |
"We found your face, but we couldn't clearly determine your mood." | |
) | |
else: | |
st.warning( | |
"We didn't detect a face in your picture. Please try again." | |
) | |
st.markdown('<div class="animated-fade">', unsafe_allow_html=True) | |
st.markdown("### Let's choose your mood manually instead.") | |
st.write( | |
"Don't worry! You can still get great song recommendations by telling us how you feel:" | |
) | |
available_emotions = list(hindi_music_recommendations.keys()) | |
selected_emotion = st.selectbox( | |
"How are you feeling right now?", | |
available_emotions, | |
format_func=lambda x: x.capitalize(), | |
) | |
if st.button("Get Music Recommendations", key="manual_mood"): | |
timestamp = time.strftime("%Y-%m-%d %H:%M:%S") | |
user_prefs["emotion_history"].append( | |
{ | |
"emotion": selected_emotion, | |
"confidence": 100.0, | |
"timestamp": timestamp, | |
"selection": "manual", | |
} | |
) | |
if len(user_prefs["emotion_history"]) > 50: | |
user_prefs["emotion_history"] = user_prefs["emotion_history"][ | |
-50: | |
] | |
save_user_preferences(user_prefs) | |
show_hindi_recommendations(selected_emotion, user_prefs) | |
st.markdown("</div>", unsafe_allow_html=True) | |
def show_hindi_recommendations(emotion, user_prefs): | |
emotion_emojis = { | |
"happy": "π", | |
"sad": "π’", | |
"angry": "π ", | |
"fear": "π¨", | |
"neutral": "π", | |
"disgust": "π€’", | |
"surprise": "π²", | |
} | |
emoji = emotion_emojis.get(emotion, "") | |
st.markdown('<div class="animated-fade">', unsafe_allow_html=True) | |
st.markdown( | |
f"<h3>{emoji} Songs for your {emotion.capitalize()} Mood</h3>", | |
unsafe_allow_html=True, | |
) | |
st.write( | |
"Here are songs that match your current mood. Click the heart to save your favorites." | |
) | |
recommendations = get_personalized_hindi_recommendations(emotion, user_prefs) | |
if not recommendations: | |
st.warning("No songs were found for this mood. Please choose another one.") | |
return | |
for i, song in enumerate(recommendations[:3]): | |
with st.container(): | |
st.markdown( | |
f""" | |
<div class="recommendation-card"> | |
<h4 class="hindi-title">{song['title']}</h4> | |
</div> | |
""", | |
unsafe_allow_html=True, | |
) | |
try: | |
st.video(song["url"]) | |
except Exception: | |
st.error(f"Sorry, we couldn't load this video: {song['title']}") | |
continue | |
col1, col2 = st.columns([1, 6]) | |
with col1: | |
st.markdown('<div class="like-button">', unsafe_allow_html=True) | |
if st.button("π", key=f"like_{emotion}_{i}"): | |
if song not in user_prefs["liked_songs"]: | |
user_prefs["liked_songs"].append(song) | |
st.success("Added to your favorites!") | |
save_user_preferences(user_prefs) | |
st.markdown("</div>", unsafe_allow_html=True) | |
if st.button("π Find Different Songs", key=f"refresh_{emotion}"): | |
st.rerun() | |
st.markdown("</div>", unsafe_allow_html=True) | |
st.markdown( | |
"<div class='footer'>Songs chosen based on your mood and what you like.</div>", | |
unsafe_allow_html=True, | |
) | |
def get_personalized_hindi_recommendations(emotion, user_prefs): | |
if emotion not in hindi_music_recommendations: | |
return [] | |
all_recommendations = hindi_music_recommendations[emotion].copy() | |
if not all_recommendations: | |
return [] | |
liked_urls = [song["url"] for song in user_prefs["liked_songs"]] | |
new_recommendations = [ | |
song for song in all_recommendations if song["url"] not in liked_urls | |
] | |
previously_liked = [ | |
song for song in all_recommendations if song["url"] in liked_urls | |
] | |
personalized = new_recommendations + previously_liked | |
if len(personalized) < 3: | |
other_emotions = [e for e in hindi_music_recommendations.keys() if e != emotion] | |
for other_emotion in other_emotions: | |
other_songs = [ | |
song | |
for song in hindi_music_recommendations[other_emotion] | |
if song["url"] not in liked_urls | |
] | |
personalized.extend(other_songs) | |
if len(personalized) >= 5: | |
break | |
if len(new_recommendations) > 3: | |
random.shuffle(new_recommendations) | |
result = new_recommendations[:3] | |
else: | |
result = new_recommendations[:] | |
if previously_liked and len(result) < 3: | |
random.shuffle(previously_liked) | |
result.extend(previously_liked[: 3 - len(result)]) | |
return result | |
def show_mood_history(): | |
st.markdown('<p class="subheader">Your Mood History</p>', unsafe_allow_html=True) | |
st.markdown( | |
'<div class="info-box">π <b>Your Personal Mood Tracker:</b> Watch how your feelings change over time. This helps us pick better songs for you.</div>', | |
unsafe_allow_html=True, | |
) | |
user_prefs = load_user_preferences() | |
history = user_prefs.get("emotion_history", []) | |
if not history: | |
st.info( | |
"You don't have any mood history yet. Try the Music Recommendation feature to start building your profile." | |
) | |
return | |
df = pd.DataFrame(history) | |
df["timestamp"] = pd.to_datetime(df["timestamp"]) | |
df["source"] = df.apply( | |
lambda row: "Manual Selection" | |
if row.get("selection") == "manual" | |
else "AI Detection", | |
axis=1, | |
) | |
st.markdown('<div class="animated-fade">', unsafe_allow_html=True) | |
st.subheader("Your Mood Over Time") | |
fig = px.line( | |
df, | |
x="timestamp", | |
y="confidence", | |
color="emotion", | |
symbol="source", | |
title="Your Mood History", | |
labels={ | |
"timestamp": "Time", | |
"confidence": "Confidence %", | |
"emotion": "Emotion", | |
}, | |
) | |
fig.update_layout( | |
plot_bgcolor="rgba(0,0,0,0)", | |
paper_bgcolor="rgba(0,0,0,0)", | |
font=dict(family="Segoe UI, Arial, sans-serif"), | |
) | |
st.plotly_chart(fig, use_container_width=True) | |
emotion_counts = df["emotion"].value_counts().reset_index() | |
emotion_counts.columns = ["Emotion", "Count"] | |
fig2 = px.pie( | |
emotion_counts, values="Count", names="Emotion", title="Your Most Common Moods" | |
) | |
fig2.update_layout( | |
plot_bgcolor="rgba(0,0,0,0)", | |
paper_bgcolor="rgba(0,0,0,0)", | |
font=dict(family="Segoe UI, Arial, sans-serif"), | |
) | |
st.plotly_chart(fig2, use_container_width=True) | |
st.markdown("</div>", unsafe_allow_html=True) | |
st.markdown('<div class="animated-fade">', unsafe_allow_html=True) | |
st.subheader("Your Recent Mood Detections") | |
recent_df = df.sort_values("timestamp", ascending=False).head(10) | |
recent_df["Date"] = recent_df["timestamp"].dt.strftime("%Y-%m-%d") | |
recent_df["Time"] = recent_df["timestamp"].dt.strftime("%H:%M:%S") | |
recent_df = recent_df.rename( | |
columns={ | |
"emotion": "Mood", | |
"confidence": "Confidence %", | |
"source": "Detection Method", | |
} | |
) | |
st.dataframe( | |
recent_df[["Date", "Time", "Mood", "Confidence %", "Detection Method"]], | |
use_container_width=True, | |
hide_index=True, | |
) | |
st.markdown("</div>", unsafe_allow_html=True) | |
def main(): | |
load_css() | |
if GPU_AVAILABLE: | |
st.sidebar.markdown("---") | |
st.sidebar.markdown('<div class="sidebar-header">π₯ GPU Acceleration Active</div>', unsafe_allow_html=True) | |
st.sidebar.info(f"Using GPU for faster processing:\n{GPU_INFO}") | |
menu = ["Home", "Music Recommendation", "Mood History"] | |
with st.sidebar: | |
st.markdown( | |
'<div class="sidebar-header" style="text-align: center;">Menu</div>', unsafe_allow_html=True | |
) | |
choice = st.selectbox("Choose a Page", menu) | |
st.markdown("---") | |
st.markdown( | |
'<div class="sidebar-header">How It Works</div>', unsafe_allow_html=True | |
) | |
st.markdown( | |
""" | |
<div class="step-container"> | |
<div class="step-number">1</div> | |
<div class="step-content">Take a photo or select your mood</div> | |
</div> | |
<div class="step-container"> | |
<div class="step-number">2</div> | |
<div class="step-content">Our AI analyzes your feelings</div> | |
</div> | |
<div class="step-container"> | |
<div class="step-number">3</div> | |
<div class="step-content">Get songs that match your mood</div> | |
</div> | |
""", | |
unsafe_allow_html=True, | |
) | |
st.markdown("---") | |
st.markdown('<div class="sidebar-header">About</div>', unsafe_allow_html=True) | |
st.write( | |
"We use AI to understand your emotions and suggest music that fits your mood." | |
) | |
if choice == "Home": | |
st.markdown( | |
'<h1 class="main-header">Music Recommendation System</h1>', | |
unsafe_allow_html=True, | |
) | |
st.markdown( | |
""" | |
<div class="info-box"> | |
Welcome to your personal music recommendation system! This app uses AI to detect your mood and suggest songs that match how you feel right now. | |
</div> | |
""", | |
unsafe_allow_html=True, | |
) | |
st.markdown('<div class="animated-fade">', unsafe_allow_html=True) | |
st.markdown('<p class="subheader">Features</p>', unsafe_allow_html=True) | |
col1, col2 = st.columns(2) | |
with col1: | |
st.markdown( | |
""" | |
<div class="feature-card"> | |
<div class="feature-icon">π</div> | |
<h3>Mood Detection</h3> | |
<p>Our AI detects your emotions from a single photo.</p> | |
</div> | |
""", | |
unsafe_allow_html=True, | |
) | |
st.markdown( | |
""" | |
<div class="feature-card"> | |
<div class="feature-icon">πΌ</div> | |
<h3>Music Recommendations</h3> | |
<p>Get song recommendations based on your mood.</p> | |
</div> | |
""", | |
unsafe_allow_html=True, | |
) | |
with col2: | |
st.markdown( | |
""" | |
<div class="feature-card"> | |
<div class="feature-icon">π</div> | |
<h3>Save Favorites</h3> | |
<p>Choose songs you love to create your collection.</p> | |
</div> | |
""", | |
unsafe_allow_html=True, | |
) | |
st.markdown( | |
""" | |
<div class="feature-card"> | |
<div class="feature-icon">π</div> | |
<h3>Track Your Moods</h3> | |
<p>Watch your feelings change over time with charts.</p> | |
</div> | |
""", | |
unsafe_allow_html=True, | |
) | |
st.markdown("### Available Moods") | |
mood_col1, mood_col2 = st.columns(2) | |
with mood_col1: | |
st.markdown( | |
""" | |
- π **Happy** - Cheerful songs to boost your mood. | |
- π’ **Sad** - Emotional songs for your deep moments. | |
- π **Angry** - Strong tracks to match your energy. | |
""" | |
) | |
with mood_col2: | |
st.markdown( | |
""" | |
- π **Neutral** - Calming songs for everyday listening. | |
- π² **Surprise** - Tracks to spark your curiosity. | |
- π€’ **Disgust** - Cheerful songs to lift your mood. | |
""" | |
) | |
st.markdown("</div>", unsafe_allow_html=True) | |
col1, col2 = st.columns([1, 1]) | |
with col1: | |
if st.button("πΌ Get Music Recommendations"): | |
st.session_state.choice = "Music Recommendation" | |
st.rerun() | |
with col2: | |
if st.button("π View Your Mood History"): | |
st.session_state.choice = "Mood History" | |
st.rerun() | |
elif choice == "Music Recommendation": | |
music_recommendation() | |
elif choice == "Mood History": | |
show_mood_history() | |
if __name__ == "__main__": | |
main() | |