ideas / index.html
geadmin's picture
Add 1 files
344df93 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ElevenLabs AI Voice Cloning Studio</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">
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
body {
font-family: 'Inter', sans-serif;
background-color: #f8fafc;
}
.gradient-bg {
background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 50%, #d946ef 100%);
}
.waveform {
background: repeating-linear-gradient(
90deg,
#e2e8f0,
#e2e8f0 2px,
transparent 2px,
transparent 4px
);
height: 60px;
}
.voice-card:hover {
transform: translateY(-5px);
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
}
.recording {
animation: pulse 1.5s infinite;
}
@keyframes pulse {
0% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.7); }
70% { box-shadow: 0 0 0 10px rgba(239, 68, 68, 0); }
100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0); }
}
.play-btn {
transition: all 0.3s ease;
}
.play-btn:hover {
transform: scale(1.1);
}
/* Audio visualization */
.audio-visualizer {
display: flex;
align-items: flex-end;
height: 60px;
gap: 2px;
margin-top: 10px;
}
.audio-bar {
background-color: #6366f1;
width: 4px;
border-radius: 2px;
transition: height 0.1s ease;
}
/* Progress bar */
.progress-container {
width: 100%;
height: 4px;
background-color: #e2e8f0;
border-radius: 2px;
margin-top: 10px;
}
.progress-bar {
height: 100%;
background-color: #6366f1;
border-radius: 2px;
width: 0%;
transition: width 0.1s linear;
}
</style>
</head>
<body>
<div class="min-h-screen">
<!-- Header -->
<header class="gradient-bg text-white">
<div class="container mx-auto px-4 py-6">
<div class="flex justify-between items-center">
<div class="flex items-center space-x-2">
<i class="fas fa-robot text-3xl"></i>
<h1 class="text-2xl font-bold">ElevenLabs Voice Studio</h1>
</div>
<div class="flex items-center space-x-4">
<button class="px-4 py-2 bg-white text-indigo-600 rounded-lg font-medium hover:bg-gray-100 transition">
<i class="fas fa-key mr-2"></i>API Key
</button>
<button class="px-4 py-2 bg-indigo-700 text-white rounded-lg font-medium hover:bg-indigo-800 transition">
<i class="fas fa-user mr-2"></i>Account
</button>
</div>
</div>
</div>
</header>
<!-- Main Content -->
<main class="container mx-auto px-4 py-8">
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
<!-- Left Sidebar - Voice Management -->
<div class="lg:col-span-1 bg-white rounded-xl shadow-md p-6">
<div class="flex justify-between items-center mb-6">
<h2 class="text-xl font-semibold text-gray-800">My Voices</h2>
<button id="newVoiceBtn" class="px-3 py-1 bg-indigo-600 text-white rounded-lg text-sm hover:bg-indigo-700 transition">
<i class="fas fa-plus mr-1"></i> New
</button>
</div>
<div class="space-y-4">
<!-- Voice Cards -->
<div class="voice-card bg-gray-50 rounded-lg p-4 border border-gray-200 transition duration-300 cursor-pointer" data-voice="Professional Male">
<div class="flex items-center space-x-3">
<div class="w-12 h-12 rounded-full bg-indigo-100 flex items-center justify-center">
<i class="fas fa-user text-indigo-600"></i>
</div>
<div>
<h3 class="font-medium text-gray-800">Professional Male</h3>
<p class="text-xs text-gray-500">English • Standard</p>
</div>
</div>
<div class="mt-3 flex justify-between items-center">
<span class="text-xs px-2 py-1 bg-green-100 text-green-800 rounded">Active</span>
<div class="flex space-x-2">
<button class="text-gray-500 hover:text-indigo-600 play-voice-btn">
<i class="fas fa-play play-btn"></i>
</button>
<button class="text-gray-500 hover:text-indigo-600">
<i class="fas fa-edit"></i>
</button>
</div>
</div>
</div>
<div class="voice-card bg-gray-50 rounded-lg p-4 border border-gray-200 transition duration-300 cursor-pointer" data-voice="Friendly Female">
<div class="flex items-center space-x-3">
<div class="w-12 h-12 rounded-full bg-pink-100 flex items-center justify-center">
<i class="fas fa-user text-pink-600"></i>
</div>
<div>
<h3 class="font-medium text-gray-800">Friendly Female</h3>
<p class="text-xs text-gray-500">English • Conversational</p>
</div>
</div>
<div class="mt-3 flex justify-between items-center">
<span class="text-xs px-2 py-1 bg-gray-100 text-gray-800 rounded">Inactive</span>
<div class="flex space-x-2">
<button class="text-gray-500 hover:text-indigo-600 play-voice-btn">
<i class="fas fa-play play-btn"></i>
</button>
<button class="text-gray-500 hover:text-indigo-600">
<i class="fas fa-edit"></i>
</button>
</div>
</div>
</div>
<div class="voice-card bg-gray-50 rounded-lg p-4 border border-gray-200 transition duration-300 cursor-pointer" data-voice="British Narrator">
<div class="flex items-center space-x-3">
<div class="w-12 h-12 rounded-full bg-purple-100 flex items-center justify-center">
<i class="fas fa-user text-purple-600"></i>
</div>
<div>
<h3 class="font-medium text-gray-800">British Narrator</h3>
<p class="text-xs text-gray-500">English • British</p>
</div>
</div>
<div class="mt-3 flex justify-between items-center">
<span class="text-xs px-2 py-1 bg-gray-100 text-gray-800 rounded">Inactive</span>
<div class="flex space-x-2">
<button class="text-gray-500 hover:text-indigo-600 play-voice-btn">
<i class="fas fa-play play-btn"></i>
</button>
<button class="text-gray-500 hover:text-indigo-600">
<i class="fas fa-edit"></i>
</button>
</div>
</div>
</div>
</div>
<!-- Add Voice Modal (hidden by default) -->
<div id="addVoiceModal" class="hidden fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
<div class="bg-white rounded-xl p-6 w-full max-w-md">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-semibold">Create New Voice</h3>
<button id="closeModalBtn" class="text-gray-500 hover:text-gray-700">
<i class="fas fa-times"></i>
</button>
</div>
<div class="space-y-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Voice Name</label>
<input type="text" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-indigo-500 focus:border-indigo-500">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Voice Type</label>
<select class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-indigo-500 focus:border-indigo-500">
<option>Clone from audio</option>
<option>Use preset voice</option>
<option>Generate random voice</option>
</select>
</div>
<div id="audioUploadSection">
<label class="block text-sm font-medium text-gray-700 mb-1">Upload Audio Samples</label>
<div class="border-2 border-dashed border-gray-300 rounded-lg p-6 text-center">
<i class="fas fa-microphone text-3xl text-gray-400 mb-2"></i>
<p class="text-sm text-gray-500">Drag & drop audio files here or click to browse</p>
<input type="file" class="hidden" accept="audio/*">
</div>
<p class="mt-1 text-xs text-gray-500">Upload at least 30 seconds of clear speech for best results</p>
</div>
<div class="flex justify-end space-x-3 pt-4">
<button class="px-4 py-2 border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-50">Cancel</button>
<button class="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700">Create Voice</button>
</div>
</div>
</div>
</div>
</div>
<!-- Main Content - Text to Speech -->
<div class="lg:col-span-2 space-y-6">
<div class="bg-white rounded-xl shadow-md p-6">
<h2 class="text-xl font-semibold text-gray-800 mb-4">Text to Speech</h2>
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-1">Select Voice</label>
<div class="flex items-center space-x-3">
<select id="voiceSelect" class="flex-1 px-3 py-2 border border-gray-300 rounded-lg focus:ring-indigo-500 focus:border-indigo-500">
<option value="Professional Male">Professional Male</option>
<option value="Friendly Female">Friendly Female</option>
<option value="British Narrator">British Narrator</option>
</select>
<button class="px-3 py-2 bg-gray-100 text-gray-700 rounded-lg hover:bg-gray-200">
<i class="fas fa-random"></i>
</button>
</div>
</div>
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-1">Enter Text</label>
<textarea id="textInput" rows="5" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-indigo-500 focus:border-indigo-500" placeholder="Type or paste your text here...">Hello, this is a demonstration of the ElevenLabs AI voice cloning technology. The voice you're hearing has been generated by artificial intelligence.</textarea>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Stability</label>
<input type="range" min="0" max="100" value="75" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer">
<div class="flex justify-between text-xs text-gray-500 mt-1">
<span>More variable</span>
<span>More stable</span>
</div>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Clarity + Similarity</label>
<input type="range" min="0" max="100" value="65" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer">
<div class="flex justify-between text-xs text-gray-500 mt-1">
<span>More clear</span>
<span>More similar</span>
</div>
</div>
</div>
<!-- Audio Visualization -->
<div id="audioVisualization" class="hidden">
<div class="audio-visualizer" id="visualizer">
<!-- Bars will be added dynamically -->
</div>
<div class="progress-container">
<div class="progress-bar" id="progressBar"></div>
</div>
</div>
<div class="flex flex-wrap gap-3">
<button id="generateBtn" class="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 flex items-center">
<i class="fas fa-play mr-2"></i> Generate
</button>
<button id="downloadBtn" class="px-4 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 flex items-center">
<i class="fas fa-download mr-2"></i> Download
</button>
<button class="px-4 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 flex items-center">
<i class="fas fa-share-alt mr-2"></i> Share
</button>
<button id="stopBtn" class="px-4 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 flex items-center hidden">
<i class="fas fa-stop mr-2"></i> Stop
</button>
</div>
</div>
<!-- Output Section -->
<div class="bg-white rounded-xl shadow-md p-6">
<h2 class="text-xl font-semibold text-gray-800 mb-4">Generated Output</h2>
<div id="outputContainer" class="bg-gray-50 rounded-lg p-4 min-h-32">
<p class="text-gray-500 italic" id="outputPlaceholder">Your generated voice will appear here...</p>
<audio id="audioPlayer" controls class="w-full mt-4 hidden"></audio>
</div>
</div>
</div>
</div>
</main>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Modal functionality
const newVoiceBtn = document.getElementById('newVoiceBtn');
const closeModalBtn = document.getElementById('closeModalBtn');
const addVoiceModal = document.getElementById('addVoiceModal');
newVoiceBtn.addEventListener('click', () => {
addVoiceModal.classList.remove('hidden');
});
closeModalBtn.addEventListener('click', () => {
addVoiceModal.classList.add('hidden');
});
// Voice synthesis functionality
const generateBtn = document.getElementById('generateBtn');
const stopBtn = document.getElementById('stopBtn');
const downloadBtn = document.getElementById('downloadBtn');
const textInput = document.getElementById('textInput');
const voiceSelect = document.getElementById('voiceSelect');
const outputPlaceholder = document.getElementById('outputPlaceholder');
const audioPlayer = document.getElementById('audioPlayer');
const audioVisualization = document.getElementById('audioVisualization');
const visualizer = document.getElementById('visualizer');
const progressBar = document.getElementById('progressBar');
let speechSynthesis = window.speechSynthesis;
let utterance = null;
let isPlaying = false;
// Create audio visualization bars
for (let i = 0; i < 50; i++) {
const bar = document.createElement('div');
bar.className = 'audio-bar';
bar.style.height = `${Math.random() * 30 + 10}px`;
visualizer.appendChild(bar);
}
// Animate visualization bars
function animateBars() {
const bars = visualizer.querySelectorAll('.audio-bar');
bars.forEach(bar => {
const newHeight = Math.random() * 30 + 10;
bar.style.height = `${newHeight}px`;
});
if (isPlaying) {
requestAnimationFrame(animateBars);
}
}
// Generate voice
generateBtn.addEventListener('click', () => {
const text = textInput.value.trim();
if (!text) return;
const selectedVoice = voiceSelect.value;
// Update UI
outputPlaceholder.textContent = `Generating "${selectedVoice}" voice...`;
audioVisualization.classList.remove('hidden');
generateBtn.classList.add('hidden');
stopBtn.classList.remove('hidden');
isPlaying = true;
// Create speech synthesis utterance
utterance = new SpeechSynthesisUtterance(text);
// Set voice properties based on selection
switch(selectedVoice) {
case 'Professional Male':
utterance.rate = 1.0;
utterance.pitch = 0.9;
break;
case 'Friendly Female':
utterance.rate = 1.1;
utterance.pitch = 1.2;
break;
case 'British Narrator':
utterance.rate = 0.95;
utterance.pitch = 0.85;
break;
}
// Start animation
animateBars();
// Update progress bar
let startTime = Date.now();
let estimatedDuration = text.length * 50; // Rough estimate (ms)
const progressInterval = setInterval(() => {
const elapsed = Date.now() - startTime;
const progress = Math.min(elapsed / estimatedDuration * 100, 100);
progressBar.style.width = `${progress}%`;
if (progress >= 100) {
clearInterval(progressInterval);
}
}, 100);
// On speech end
utterance.onend = () => {
isPlaying = false;
generateBtn.classList.remove('hidden');
stopBtn.classList.add('hidden');
outputPlaceholder.textContent = `Voice generation complete for "${selectedVoice}"`;
clearInterval(progressInterval);
};
// On speech error
utterance.onerror = (event) => {
console.error('Speech synthesis error:', event);
isPlaying = false;
generateBtn.classList.remove('hidden');
stopBtn.classList.add('hidden');
outputPlaceholder.textContent = 'Error generating voice. Please try again.';
clearInterval(progressInterval);
};
// Speak the text
speechSynthesis.speak(utterance);
});
// Stop generation
stopBtn.addEventListener('click', () => {
if (speechSynthesis.speaking) {
speechSynthesis.cancel();
isPlaying = false;
generateBtn.classList.remove('hidden');
stopBtn.classList.add('hidden');
outputPlaceholder.textContent = 'Voice generation stopped';
}
});
// Play voice samples from cards
const playButtons = document.querySelectorAll('.play-voice-btn');
playButtons.forEach(button => {
button.addEventListener('click', (e) => {
e.stopPropagation();
const card = button.closest('.voice-card');
const voiceName = card.dataset.voice;
const sampleText = `This is a sample of the ${voiceName} voice from ElevenLabs.`;
const utterance = new SpeechSynthesisUtterance(sampleText);
// Set voice properties based on selection
switch(voiceName) {
case 'Professional Male':
utterance.rate = 1.0;
utterance.pitch = 0.9;
break;
case 'Friendly Female':
utterance.rate = 1.1;
utterance.pitch = 1.2;
break;
case 'British Narrator':
utterance.rate = 0.95;
utterance.pitch = 0.85;
break;
}
speechSynthesis.speak(utterance);
});
});
// Download functionality (simulated)
downloadBtn.addEventListener('click', () => {
const text = textInput.value.trim();
if (!text) return;
const selectedVoice = voiceSelect.value;
outputPlaceholder.textContent = `Preparing download for "${selectedVoice}" voice...`;
// Simulate download preparation
setTimeout(() => {
outputPlaceholder.textContent = `Download ready for "${selectedVoice}" (simulated)`;
// In a real implementation, this would download the audio file
// For now, we'll just show a message
alert('In a real implementation, this would download the generated voice as an MP3 file.');
}, 1500);
});
// Voice card selection
const voiceCards = document.querySelectorAll('.voice-card');
voiceCards.forEach(card => {
card.addEventListener('click', () => {
const voiceName = card.dataset.voice;
voiceSelect.value = voiceName;
// Update active state
voiceCards.forEach(c => {
c.querySelector('span').className = 'text-xs px-2 py-1 bg-gray-100 text-gray-800 rounded';
});
card.querySelector('span').className = 'text-xs px-2 py-1 bg-green-100 text-green-800 rounded';
});
});
});
</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=geadmin/ideas" style="color: #fff;text-decoration: underline;" target="_blank" >🧬 Remix</a></p></body>
</html>