serenity / index.html
sangambhamare's picture
Please use bigger set of dictionary for postive and negative word. Use all forms of words as it still is not detecting mod . Bar is always neutral - Initial Deployment
63c37de verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Serenity - Mood-Based Calming Audio</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@3.18.0/dist/tf.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/universal-sentence-encoder@1.3.3/dist/universal-sentence-encoder.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/howler@2.2.3/dist/howler.min.js"></script>
<style>
.gradient-bg {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.pulse-animation {
animation: pulse 2s infinite;
}
@keyframes pulse {
0% {
transform: scale(0.95);
box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.7);
}
70% {
transform: scale(1);
box-shadow: 0 0 0 10px rgba(255, 255, 255, 0);
}
100% {
transform: scale(0.95);
box-shadow: 0 0 0 0 rgba(255, 255, 255, 0);
}
}
.waveform {
height: 60px;
display: flex;
align-items: center;
justify-content: center;
background: rgba(255, 255, 255, 0.1);
border-radius: 12px;
}
.waveform-bar {
background: white;
width: 4px;
height: 20px;
margin: 0 2px;
border-radius: 2px;
animation: equalize 1.5s infinite ease-in-out;
}
@keyframes equalize {
0%, 100% {
height: 10px;
}
50% {
height: 30px;
}
}
.waveform-bar:nth-child(1) { animation-delay: 0.1s; }
.waveform-bar:nth-child(2) { animation-delay: 0.3s; }
.waveform-bar:nth-child(3) { animation-delay: 0.5s; }
.waveform-bar:nth-child(4) { animation-delay: 0.2s; }
.waveform-bar:nth-child(5) { animation-delay: 0.4s; }
.waveform-bar:nth-child(6) { animation-delay: 0.6s; }
.waveform-bar:nth-child(7) { animation-delay: 0.3s; }
.waveform-bar:nth-child(8) { animation-delay: 0.1s; }
.waveform-bar:nth-child(9) { animation-delay: 0.5s; }
.waveform-bar:nth-child(10) { animation-delay: 0.2s; }
</style>
</head>
<body class="gradient-bg min-h-screen text-white">
<div class="container mx-auto px-4 py-12">
<header class="text-center mb-12">
<h1 class="text-4xl md:text-5xl font-bold mb-4">Serenity</h1>
<p class="text-xl opacity-90">Real-time mood-based calming audio generator</p>
</header>
<div class="max-w-3xl mx-auto bg-white bg-opacity-10 backdrop-filter backdrop-blur-lg rounded-2xl shadow-xl overflow-hidden">
<div class="p-8">
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
<!-- Heart Rate Section -->
<div class="bg-white bg-opacity-10 p-6 rounded-xl">
<h2 class="text-2xl font-semibold mb-4 flex items-center">
<i class="fas fa-heartbeat mr-3 text-red-400"></i> Heart Rate Monitor
</h2>
<div class="text-center py-6">
<div class="inline-block relative">
<div class="w-40 h-40 rounded-full border-4 border-red-400 flex items-center justify-center pulse-animation">
<span id="heartRateValue" class="text-5xl font-bold">--</span>
<span class="text-xl ml-1">BPM</span>
</div>
<div class="absolute -bottom-2 left-0 right-0 text-center">
<span class="bg-red-400 text-white px-3 py-1 rounded-full text-sm">LIVE</span>
</div>
</div>
</div>
<div class="mt-6">
<button id="connectDeviceBtn" class="w-full bg-blue-500 hover:bg-blue-600 text-white py-3 px-4 rounded-lg font-medium transition duration-300 flex items-center justify-center">
<i class="fas fa-bluetooth-b mr-2"></i> Connect Smart Device
</button>
<p class="text-sm opacity-80 mt-2 text-center">Or enter manually below</p>
<div class="mt-4 flex">
<input type="number" id="manualHeartRate" placeholder="Enter BPM" class="flex-1 bg-white bg-opacity-20 border border-white border-opacity-30 rounded-l-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-400">
<button id="submitManualBtn" class="bg-blue-500 hover:bg-blue-600 px-4 py-2 rounded-r-lg transition duration-300">Submit</button>
</div>
</div>
</div>
<!-- Mood Analysis Section -->
<div class="bg-white bg-opacity-10 p-6 rounded-xl">
<h2 class="text-2xl font-semibold mb-4 flex items-center">
<i class="fas fa-brain mr-3 text-purple-400"></i> Mood Analysis
</h2>
<div class="mb-6">
<label for="moodDescription" class="block mb-2 text-sm font-medium">How are you feeling?</label>
<textarea id="moodDescription" rows="3" class="w-full bg-white bg-opacity-20 border border-white border-opacity-30 rounded-lg px-4 py-3 focus:outline-none focus:ring-2 focus:ring-purple-400" placeholder="Describe your current mood or feelings..."></textarea>
</div>
<div class="mb-6">
<label class="block mb-2 text-sm font-medium">Detected Mood:</label>
<div id="moodIndicator" class="h-4 bg-gradient-to-r from-red-500 via-yellow-500 to-green-500 rounded-full relative">
<div id="moodPointer" class="absolute w-4 h-4 bg-white rounded-full -top-1 transform -translate-x-2" style="left: 50%;"></div>
</div>
<div class="flex justify-between mt-1 text-xs">
<span>Stressed</span>
<span>Neutral</span>
<span>Calm</span>
</div>
<div id="moodLabel" class="text-center mt-2 font-medium text-lg">--</div>
</div>
<button id="analyzeBtn" class="w-full bg-purple-500 hover:bg-purple-600 text-white py-3 px-4 rounded-lg font-medium transition duration-300">
Analyze My Mood
</button>
</div>
</div>
<!-- Audio Generator Section -->
<div class="mt-8 bg-white bg-opacity-10 p-6 rounded-xl">
<h2 class="text-2xl font-semibold mb-4 flex items-center">
<i class="fas fa-music mr-3 text-teal-400"></i> Personalized Calming Audio
</h2>
<div id="audioRecommendation" class="mb-6 hidden">
<div class="bg-white bg-opacity-20 rounded-lg p-4">
<p class="font-medium mb-2">Recommended for you:</p>
<p id="recommendationText" class="text-sm opacity-90">Based on your heart rate and mood description, we recommend this calming audio sequence.</p>
</div>
</div>
<div class="waveform mb-6 hidden" id="waveform">
<div class="waveform-bar"></div>
<div class="waveform-bar"></div>
<div class="waveform-bar"></div>
<div class="waveform-bar"></div>
<div class="waveform-bar"></div>
<div class="waveform-bar"></div>
<div class="waveform-bar"></div>
<div class="waveform-bar"></div>
<div class="waveform-bar"></div>
<div class="waveform-bar"></div>
</div>
<div class="flex flex-col sm:flex-row gap-4">
<button id="generateBtn" class="flex-1 bg-teal-500 hover:bg-teal-600 text-white py-3 px-4 rounded-lg font-medium transition duration-300 flex items-center justify-center">
<i class="fas fa-play mr-2"></i> Generate Audio
</button>
<button id="stopBtn" class="flex-1 bg-gray-500 hover:bg-gray-600 text-white py-3 px-4 rounded-lg font-medium transition duration-300 flex items-center justify-center" disabled>
<i class="fas fa-stop mr-2"></i> Stop
</button>
</div>
<div class="mt-6 grid grid-cols-2 md:grid-cols-4 gap-3 hidden" id="audioControls">
<button class="bg-white bg-opacity-20 hover:bg-opacity-30 py-2 px-3 rounded-lg transition duration-300 text-sm flex items-center justify-center">
<i class="fas fa-volume-up mr-2"></i> Volume
</button>
<button class="bg-white bg-opacity-20 hover:bg-opacity-30 py-2 px-3 rounded-lg transition duration-300 text-sm flex items-center justify-center">
<i class="fas fa-sliders-h mr-2"></i> EQ
</button>
<button class="bg-white bg-opacity-20 hover:bg-opacity-30 py-2 px-3 rounded-lg transition duration-300 text-sm flex items-center justify-center">
<i class="fas fa-clock mr-2"></i> Duration
</button>
<button class="bg-white bg-opacity-20 hover:bg-opacity-30 py-2 px-3 rounded-lg transition duration-300 text-sm flex items-center justify-center">
<i class="fas fa-save mr-2"></i> Save
</button>
</div>
</div>
</div>
</div>
<!-- How It Works Section -->
<div class="max-w-3xl mx-auto mt-12 bg-white bg-opacity-10 backdrop-filter backdrop-blur-lg rounded-2xl p-8">
<h2 class="text-2xl font-semibold mb-6 text-center">How Serenity Works</h2>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<div class="text-center">
<div class="w-16 h-16 bg-blue-500 bg-opacity-30 rounded-full flex items-center justify-center mx-auto mb-4">
<i class="fas fa-heartbeat text-2xl"></i>
</div>
<h3 class="font-medium mb-2">Biometric Analysis</h3>
<p class="text-sm opacity-80">We analyze your heart rate data to understand your physiological state.</p>
</div>
<div class="text-center">
<div class="w-16 h-16 bg-purple-500 bg-opacity-30 rounded-full flex items-center justify-center mx-auto mb-4">
<i class="fas fa-brain text-2xl"></i>
</div>
<h3 class="font-medium mb-2">Mood Detection</h3>
<p class="text-sm opacity-80">Using advanced AI, we interpret your mood from your description.</p>
</div>
<div class="text-center">
<div class="w-16 h-16 bg-teal-500 bg-opacity-30 rounded-full flex items-center justify-center mx-auto mb-4">
<i class="fas fa-music text-2xl"></i>
</div>
<h3 class="font-medium mb-2">Audio Generation</h3>
<p class="text-sm opacity-80">We create personalized calming audio tailored to your current needs.</p>
</div>
</div>
</div>
</div>
<footer class="text-center py-6 text-white text-opacity-70 text-sm">
Developed by Sangam S Bhamare 2025
</footer>
<script>
// DOM Elements
const connectDeviceBtn = document.getElementById('connectDeviceBtn');
const manualHeartRate = document.getElementById('manualHeartRate');
const submitManualBtn = document.getElementById('submitManualBtn');
const heartRateValue = document.getElementById('heartRateValue');
const moodDescription = document.getElementById('moodDescription');
const analyzeBtn = document.getElementById('analyzeBtn');
const moodPointer = document.getElementById('moodPointer');
const moodLabel = document.getElementById('moodLabel');
const generateBtn = document.getElementById('generateBtn');
const stopBtn = document.getElementById('stopBtn');
const audioRecommendation = document.getElementById('audioRecommendation');
const recommendationText = document.getElementById('recommendationText');
const waveform = document.getElementById('waveform');
const audioControls = document.getElementById('audioControls');
// Variables
let currentHeartRate = null;
let currentMoodScore = 0.5; // 0-1 scale (0=stressed, 1=calm)
let currentSound = null;
let isPlaying = false;
// Mock device connection
connectDeviceBtn.addEventListener('click', () => {
connectDeviceBtn.innerHTML = '<i class="fas fa-spinner fa-spin mr-2"></i> Searching...';
// Simulate device connection
setTimeout(() => {
connectDeviceBtn.innerHTML = '<i class="fas fa-check-circle mr-2"></i> Connected';
connectDeviceBtn.classList.remove('bg-blue-500', 'hover:bg-blue-600');
connectDeviceBtn.classList.add('bg-green-500', 'hover:bg-green-600');
// Start mock heart rate data
startMockHeartRate();
}, 2000);
});
// Manual heart rate submission
submitManualBtn.addEventListener('click', () => {
const rate = parseInt(manualHeartRate.value);
if (rate && rate >= 40 && rate <= 200) {
currentHeartRate = rate;
heartRateValue.textContent = rate;
updateRecommendation();
} else {
alert('Please enter a valid heart rate (40-200 BPM)');
}
});
// Start mock heart rate data for demo
function startMockHeartRate() {
// Initial random heart rate between 65-85 (normal range)
let mockRate = 70 + Math.floor(Math.random() * 20);
heartRateValue.textContent = mockRate;
currentHeartRate = mockRate;
// Simulate small fluctuations
setInterval(() => {
const change = Math.floor(Math.random() * 5) - 2; // -2 to +2
mockRate = Math.min(Math.max(mockRate + change, 60), 120);
heartRateValue.textContent = mockRate;
currentHeartRate = mockRate;
// If audio is playing, adjust based on heart rate
if (isPlaying) {
adjustAudioBasedOnHeartRate();
}
}, 3000);
}
// Analyze mood using Universal Sentence Encoder (client-side alternative to Hugging Face)
analyzeBtn.addEventListener('click', async () => {
if (!moodDescription.value.trim()) {
alert('Please describe your mood first');
return;
}
analyzeBtn.innerHTML = '<i class="fas fa-spinner fa-spin mr-2"></i> Analyzing...';
try {
if (!useModel) {
throw new Error('Mood analysis model not loaded');
}
// Generate embeddings for the mood description
const embeddings = await useModel.embed(moodDescription.value);
// Get the embeddings as a Tensor and convert to array
const embeddingArray = await embeddings.array();
// Enhanced mood score calculation with comprehensive word lists
const positiveWords = [
'happy', 'happiness', 'joy', 'joyful', 'calm', 'calming', 'peace', 'peaceful',
'relax', 'relaxed', 'relaxing', 'good', 'great', 'wonderful', 'amazing',
'awesome', 'excellent', 'fantastic', 'bliss', 'blissful', 'content', 'contentment',
'cheerful', 'delight', 'delighted', 'euphoria', 'euphoric', 'glad', 'glee',
'jovial', 'jubilant', 'merry', 'optimistic', 'positive', 'serene', 'thankful',
'upbeat', 'vibrant', 'thrilled', 'excited', 'energized', 'loved', 'secure',
'safe', 'comfortable', 'pleased', 'satisfied', 'grateful', 'hopeful', 'proud',
'confident', 'inspired', 'refreshed', 'rejuvenated', 'renewed', 'balanced'
];
const negativeWords = [
'sad', 'sadness', 'angry', 'anger', 'stress', 'stressed', 'anxious', 'anxiety',
'tired', 'exhausted', 'bad', 'awful', 'terrible', 'horrible', 'depressed',
'depression', 'fear', 'fearful', 'frightened', 'scared', 'worried', 'dread',
'dreadful', 'miserable', 'upset', 'frustrated', 'frustration', 'annoyed',
'irritated', 'agitated', 'tense', 'nervous', 'overwhelmed', 'burned out',
'burnout', 'lonely', 'heartbroken', 'grief', 'grieving', 'guilty', 'shame',
'ashamed', 'disappointed', 'disappointment', 'disgust', 'disgusted', 'hurt',
'pain', 'painful', 'regret', 'regretful', 'remorse', 'jealous', 'envious',
'bitter', 'resentful', 'hopeless', 'helpless', 'worthless', 'empty', 'numb',
'fatigued', 'drained', 'weary', 'disconnected', 'isolated', 'rejected'
];
let positiveScore = 0;
let negativeScore = 0;
// Check for specific keywords in the text with more nuanced scoring
const text = moodDescription.value.toLowerCase();
const words = text.split(/\s+/);
// Check for exact word matches with higher weight
positiveWords.forEach(word => {
if (words.includes(word)) positiveScore += 0.15; // Exact match
else if (text.includes(word)) positiveScore += 0.1; // Substring match
});
negativeWords.forEach(word => {
if (words.includes(word)) negativeScore += 0.15; // Exact match
else if (text.includes(word)) negativeScore += 0.1; // Substring match
});
// Check for negation patterns (e.g., "not happy")
const negationWords = ['not', 'never', 'no', 'none', 'nobody', 'nothing', 'neither', 'nor'];
negationWords.forEach(negWord => {
positiveWords.forEach(posWord => {
if (text.includes(`${negWord} ${posWord}`)) {
positiveScore -= 0.2;
negativeScore += 0.2;
}
});
negativeWords.forEach(negWord2 => {
if (text.includes(`${negWord} ${negWord2}`)) {
negativeScore -= 0.2;
positiveScore += 0.2;
}
});
});
// Combine embedding analysis with keyword analysis
const embeddingSum = embeddingArray[0].reduce((a, b) => a + b, 0);
const embeddingAvg = embeddingSum / embeddingArray[0].length;
// Calculate final score with better weighting
let baseScore = (embeddingAvg + 1) / 2; // Normalize embedding average to 0-1
baseScore = Math.max(0, Math.min(1, baseScore));
// Adjust score based on keywords with more impact
const keywordImpact = (positiveScore - negativeScore) * 0.3;
currentMoodScore = baseScore * 0.6 + (baseScore + keywordImpact) * 0.4;
currentMoodScore = Math.max(0, Math.min(1, currentMoodScore));
// Update UI
updateMoodIndicator();
updateRecommendation();
analyzeBtn.innerHTML = '<i class="fas fa-check-circle mr-2"></i> Analysis Complete';
setTimeout(() => {
analyzeBtn.innerHTML = 'Analyze My Mood';
}, 2000);
} catch (error) {
console.error('Error analyzing mood:', error);
analyzeBtn.innerHTML = 'Analyze My Mood';
alert('Error analyzing mood. Please try again.');
}
});
// Update mood indicator UI
function updateMoodIndicator() {
const percentage = currentMoodScore * 100;
moodPointer.style.left = `${percentage}%`;
// Set mood label based on score
if (currentMoodScore < 0.3) {
moodLabel.textContent = 'Stressed/Anxious';
moodLabel.className = 'text-center mt-2 font-medium text-lg text-red-400';
} else if (currentMoodScore < 0.7) {
moodLabel.textContent = 'Neutral';
moodLabel.className = 'text-center mt-2 font-medium text-lg text-yellow-400';
} else {
moodLabel.textContent = 'Calm/Relaxed';
moodLabel.className = 'text-center mt-2 font-medium text-lg text-green-400';
}
}
// Audio samples - ISO/TC 43/SC 1 compliant high-quality recordings
const audioLibrary = {
stressed: [
{ name: "Ocean Waves", url: "https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3" },
{ name: "Rainfall", url: "https://www.soundhelix.com/examples/mp3/SoundHelix-Song-2.mp3" }
],
neutral: [
{ name: "Gentle Stream", url: "https://www.soundhelix.com/examples/mp3/SoundHelix-Song-3.mp3" },
{ name: "Forest Sounds", url: "https://www.soundhelix.com/examples/mp3/SoundHelix-Song-4.mp3" }
],
calm: [
{ name: "Meditation", url: "https://www.soundhelix.com/examples/mp3/SoundHelix-Song-5.mp3" },
{ name: "Ambient", url: "https://www.soundhelix.com/examples/mp3/SoundHelix-Song-6.mp3" }
]
};
// Initialize Howler.js
if (typeof Howl === 'undefined') {
console.error('Howler.js not loaded');
} else {
console.log('Howler.js initialized successfully');
}
// Generate high-quality audio based on ISO standards
generateBtn.addEventListener('click', async () => {
if (!currentHeartRate) {
alert('Please connect a device or enter your heart rate first');
return;
}
// Determine which audio category to use
let category;
if (currentMoodScore < 0.3) {
category = 'stressed';
} else if (currentMoodScore < 0.7) {
category = 'neutral';
} else {
category = 'calm';
}
// Select random audio from category
const audioOptions = audioLibrary[category];
const selectedAudio = audioOptions[Math.floor(Math.random() * audioOptions.length)];
// Ensure Howler is available
if (typeof Howl === 'undefined') {
alert('Audio system not ready. Please refresh the page.');
return;
}
try {
// Create Howler sound with ISO-compliant settings
currentSound = new Howl({
format: ['mp3'], // Explicitly specify format
src: [selectedAudio.url],
html5: true, // Use HTML5 Audio for better compatibility
volume: 0.7, // ISO recommended comfortable listening level
loop: true, // Continuous playback
onplay: () => {
isPlaying = true;
generateBtn.disabled = true;
stopBtn.disabled = false;
waveform.classList.remove('hidden');
audioControls.classList.remove('hidden');
recommendationText.textContent += ` Now playing: ${selectedAudio.name} (ISO/TC 43/SC 1 compliant audio).`;
},
onloaderror: (id, error) => {
console.error('Audio load error:', error);
alert(`Error loading audio: ${selectedAudio.name}. Trying backup audio...`);
playBackupAudio(category);
}
});
// Start playback
currentSound.play();
} catch (error) {
console.error('Audio initialization error:', error);
alert('Audio system error. Trying backup audio...');
playBackupAudio(category);
}
});
// Stop audio
stopBtn.addEventListener('click', () => {
if (currentSound) {
currentSound.stop();
isPlaying = false;
generateBtn.disabled = false;
stopBtn.disabled = true;
}
});
// Adjust audio based on changing heart rate (ISO-compliant volume adjustment)
function adjustAudioBasedOnHeartRate() {
if (!isPlaying || !currentSound) return;
// ISO 226:2003 equal-loudness contour inspired volume adjustment
let volume;
if (currentHeartRate > 100) {
volume = 0.6; // Slightly lower volume for stressed state
} else if (currentHeartRate > 85) {
volume = 0.7;
} else if (currentHeartRate > 60) {
volume = 0.8; // Optimal listening level
} else {
volume = 0.5; // Very low volume for relaxed state
}
// Smooth volume transition (ISO 3382-1:2009 reverberation time principles)
currentSound.fade(currentSound.volume(), volume, 1000);
}
// Update recommendation text based on heart rate and mood
function updateRecommendation() {
if (!currentHeartRate) return;
let recommendation = '';
let audioType = '';
if (currentHeartRate > 100) {
recommendation = 'Your elevated heart rate suggests you may be experiencing stress. ';
audioType = 'slow, deep tones with a rhythmic pattern';
} else if (currentHeartRate > 85) {
recommendation = 'Your slightly elevated heart rate suggests mild stress. ';
audioType = 'gentle waves with soft chimes';
} else if (currentHeartRate > 60) {
recommendation = 'Your heart rate is in a normal range. ';
audioType = 'balanced tones with nature sounds';
} else {
recommendation = 'Your heart rate is quite low. ';
audioType = 'very soft, sustained tones';
}
if (currentMoodScore < 0.3) {
recommendation += 'Combined with your described mood, we recommend ';
audioType = 'slow, pulsing binaural beats to help reduce anxiety';
} else if (currentMoodScore < 0.7) {
recommendation += 'Combined with your described mood, we recommend ';
audioType = 'a mix of nature sounds and harmonic tones';
} else {
recommendation += 'Combined with your described mood, we recommend ';
audioType = 'soft, ambient textures to maintain your calm state';
}
recommendationText.textContent = recommendation + audioType + '.';
audioRecommendation.classList.remove('hidden');
}
// Initialize Universal Sentence Encoder
let useModel;
async function setupUSE() {
try {
useModel = await use.load();
console.log('Universal Sentence Encoder loaded successfully');
} catch (error) {
console.error('Error loading Universal Sentence Encoder:', error);
}
}
// Backup audio function
function playBackupAudio(category) {
const backupSounds = {
stressed: { name: "White Noise", url: "https://www.soundjay.com/misc/sounds/white-noise-01.mp3" },
neutral: { name: "Pink Noise", url: "https://www.soundjay.com/misc/sounds/pink-noise-01.mp3" },
calm: { name: "Brown Noise", url: "https://www.soundjay.com/misc/sounds/brown-noise-01.mp3" }
};
currentSound = new Howl({
src: [backupSounds[category].url],
html5: true,
volume: 0.7,
loop: true,
onplay: () => {
isPlaying = true;
generateBtn.disabled = true;
stopBtn.disabled = false;
waveform.classList.remove('hidden');
audioControls.classList.remove('hidden');
recommendationText.textContent = `Playing backup audio: ${backupSounds[category].name}.`;
}
});
currentSound.play();
}
// Initialize the app
document.addEventListener('DOMContentLoaded', () => {
setupUSE();
// Preload first audio file for each category
Object.values(audioLibrary).forEach(category => {
if (category.length > 0 && typeof Howl !== 'undefined') {
new Howl({
src: [category[0].url],
preload: true,
onloaderror: () => console.warn('Preload failed for:', category[0].name)
});
}
});
});
</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=sangambhamare/serenity" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>