VOICECLONE / index.html
luis5463's picture
This web page has three parts. First, an upload area where the user uploads an audio sample to create a voice clone. After upload, the backend extracts and stores the speaker’s voice and returns an identifier for that voice. Second, a text input area where the user types the text they want the cloned voice to speak. Third, a results area where the page shows the generated audio and provides a download link.
0ddd5c8 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>VoiceCloneAI - Your Digital Doppelgänger</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
<script src="https://unpkg.com/feather-icons"></script>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@latest"></script>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/speech-commands"></script>
<script src="https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.waves.min.js"></script>
<style>
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
background: linear-gradient(135deg, #0f0f23 0%, #1a1a2e 50%, #16213e 100%);
color: #ffffff;
min-height: 100vh;
}
.wave-bg {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -1;
opacity: 0.3;
}
.glass-card {
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border-radius: 24px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
border: 1px solid rgba(255, 255, 255, 0.1);
}
.recording {
animation: pulse 2s infinite;
}
@keyframes pulse {
0% {
box-shadow: 0 0 0 0 rgba(99, 102, 241, 0.6),
0 0 0 0 rgba(139, 92, 246, 0.4);
}
50% {
box-shadow: 0 0 0 20px rgba(99, 102, 241, 0.2),
0 0 0 40px rgba(139, 92, 246, 0.1);
}
100% {
box-shadow: 0 0 0 40px rgba(99, 102, 241, 0),
0 0 0 60px rgba(139, 92, 246, 0);
}
}
.btn-gradient {
background: linear-gradient(135deg, #6366F1 0%, #8B5CF6 50%, #EC4899 100%);
color: white;
transition: all 0.4s ease;
border: none;
position: relative;
overflow: hidden;
}
.btn-gradient:hover {
transform: translateY(-3px);
box-shadow: 0 15px 30px rgba(99, 102, 241, 0.3);
}
.btn-gradient::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
transition: left 0.5s;
}
.btn-gradient:hover::before {
left: 100%;
}
.feature-card {
transition: all 0.4s ease;
background: rgba(255, 255, 255, 0.03);
border: 1px solid rgba(255, 255, 255, 0.1);
}
.feature-card:hover {
transform: translateY(-8px) scale(1.02);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.4);
background: rgba(255, 255, 255, 0.08);
border: 1px solid rgba(99, 102, 241, 0.3);
}
.gradient-text {
background: linear-gradient(135deg, #6366F1 0%, #8B5CF6 30%, #EC4899 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.neon-glow {
text-shadow: 0 0 10px rgba(99, 102, 241, 0.5),
0 0 20px rgba(99, 102, 241, 0.3),
0 0 40px rgba(99, 102, 241, 0.1);
}
.audio-wave {
background: linear-gradient(90deg,
#6366F1 0%,
#8B5CF6 25%,
#EC4899 50%,
#F59E0B 75%,
#10B981 100%);
height: 4px;
border-radius: 2px;
animation: wave 2s ease-in-out infinite;
}
@keyframes wave {
0%, 100% { transform: scaleX(0.8); opacity: 0.7; }
50% { transform: scaleX(1); opacity: 1; }
}
.floating {
animation: floating 3s ease-in-out infinite;
}
@keyframes floating {
0%, 100% { transform: translateY(0px); }
50% { transform: translateY(-10px); }
}
</style>
</head>
<body class="bg-gray-50">
<div id="wave-bg" class="wave-bg"></div>
<div class="min-h-screen flex flex-col items-center justify-start px-4 pt-12">
<header class="w-full max-w-6xl mx-auto py-8">
<div class="flex flex-col items-center">
<div class="w-24 h-24 bg-gradient-to-br from-indigo-500 via-purple-500 to-pink-500 rounded-full flex items-center justify-center shadow-2xl mb-8 floating">
<i data-feather="mic" class="w-12 h-12 text-white"></i>
</div>
<h1 class="text-6xl font-black mb-4 gradient-text neon-glow">VoiceCloneAI</h1>
<p class="text-2xl text-gray-300 max-w-2xl text-center leading-relaxed">Transform your voice into a digital masterpiece with cutting-edge AI technology</p>
<div class="mt-6 audio-wave w-32"></div>
</div>
</header>
<main class="w-full max-w-6xl glass-card p-12 mb-12">
<div class="grid lg:grid-cols-2 gap-12">
<div class="space-y-8">
<div>
<h2 class="text-3xl font-bold gradient-text mb-3">Create Your Voice Clone</h2>
<p class="text-gray-300 text-lg">Record or upload samples to train your unique voice model</p>
</div>
<div class="flex flex-col items-center space-y-6">
<div class="relative">
<div id="recordBtn" class="w-28 h-28 rounded-full bg-gradient-to-br from-indigo-500 to-pink-500 flex items-center justify-center cursor-pointer shadow-2xl hover:shadow-3xl transition-all duration-300">
<i data-feather="mic" class="w-12 h-12 text-white"></i>
</div>
<div class="absolute -bottom-8 left-0 right-0 text-center text-sm text-gray-400" id="recordingStatus">Click to record</div>
</div>
<div class="w-full h-2 bg-gray-700 rounded-full overflow-hidden">
<div id="soundWave" class="h-full bg-gradient-to-r from-indigo-500 via-purple-500 to-pink-500 rounded-full w-0 transition-all duration-100"></div>
</div>
<div class="relative w-full text-center">
<span class="text-gray-400 text-lg font-medium">or</span>
</div>
<div class="w-full">
<label class="flex flex-col items-center px-6 py-8 bg-gray-800 rounded-xl border-2 border-dashed border-gray-600 cursor-pointer hover:border-indigo-400 transition-all duration-300">
<div class="flex items-center space-x-3 text-indigo-400">
<i data-feather="upload" class="w-6 h-6"></i>
<span class="text-lg font-medium">Upload Voice File</span>
</div>
<input type="file" id="voiceUpload" accept="audio/*" class="hidden" />
<p class="mt-2 text-sm text-gray-400">MP3, WAV, OGG (max 50MB)</p>
</label>
</div>
</div>
<div class="flex items-center space-x-3 text-gray-400 bg-gray-800 p-4 rounded-xl">
<i data-feather="info" class="w-5 h-5 text-indigo-400"></i>
<span class="text-sm">Find a quiet place and speak naturally for best results</span>
</div>
</div>
<div class="space-y-8">
<div>
<h2 class="text-3xl font-bold gradient-text mb-3">Your Voice Clone</h2>
<p class="text-gray-300 text-lg">Preview and customize your generated voice</p>
</div>
<div class="bg-gray-800 rounded-xl p-8 min-h-48 flex flex-col items-center justify-center border border-gray-700">
<div id="voicePreview" class="text-center w-full">
<div class="flex flex-col items-center justify-center">
<div class="w-20 h-20 bg-gradient-to-br from-gray-600 to-gray-700 rounded-full flex items-center justify-center mb-4">
<i data-feather="user" class="w-8 h-8 text-gray-400"></i>
</div>
<p class="text-gray-400 mb-6">Your voice clone will be generated here</p>
</div>
<div class="w-full mb-6">
<textarea id="textToGenerate" class="w-full p-4 bg-gray-700 border border-gray-600 rounded-xl resize-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 text-white placeholder-gray-400" rows="3" placeholder="Enter text to generate with your voice clone (like ElevenLabs)"></textarea>
</div>
<div id="voiceParams" class="w-full space-y-4 hidden">
<div>
<label class="block text-sm text-gray-300 mb-2">Voice Similarity</label>
<input type="range" min="0" max="100" value="85" class="w-full accent-indigo-500 bg-gray-600 rounded-lg">
</div>
<div>
<label class="block text-sm text-gray-300 mb-2">Pitch & Emotion</label>
<input type="range" min="0" max="100" value="60" class="w-full accent-purple-500 bg-gray-600 rounded-lg">
</div>
<div>
<label class="block text-sm text-gray-300 mb-2">Speed & Tone</label>
<input type="range" min="50" max="150" value="100" class="w-full accent-pink-500 bg-gray-600 rounded-lg">
</div>
</div>
</div>
</div>
<div class="flex flex-wrap gap-4">
<button id="trainBtn" class="px-8 py-4 btn-gradient rounded-xl flex items-center space-x-3 text-lg font-medium">
<i data-feather="cpu" class="w-5 h-5"></i>
<span>Train Model</span>
</button>
<button id="generateBtn" class="px-8 py-4 btn-gradient rounded-xl flex items-center space-x-3 text-lg font-medium" style="background: linear-gradient(135deg, #10B981 0%, #3B82F6 50%, #6366F1 100%);">
<i data-feather="play" class="w-5 h-5"></i>
<span>Generate Voice</span>
</button>
<button id="downloadBtn" class="px-8 py-4 border border-gray-600 text-gray-300 rounded-xl hover:bg-gray-700 hover:border-indigo-400 transition-all duration-300 flex items-center space-x-3 text-lg font-medium">
<i data-feather="download" class="w-5 h-5"></i>
<span>Download</span>
</button>
</div>
</div>
</div>
</main>
<section class="w-full max-w-6xl glass-card p-12 mb-12">
<h2 class="text-3xl font-bold gradient-text mb-8 text-center">Powered by State-of-the-Art AI Models</h2>
<div class="grid lg:grid-cols-3 gap-8">
<div class="feature-card p-8 rounded-xl">
<div class="w-16 h-16 bg-gradient-to-br from-indigo-500 to-purple-500 rounded-xl flex items-center justify-center mb-6">
<i data-feather="zap" class="w-8 h-8 text-white"></i>
</div>
<h3 class="font-bold text-xl mb-3 text-white">OpenAI Whisper</h3>
<p class="text-gray-300 leading-relaxed">Utilizing OpenAI's Whisper for superior speech recognition and transcription accuracy in multiple languages</p>
</div>
<div class="feature-card p-8 rounded-xl">
<div class="w-16 h-16 bg-gradient-to-br from-purple-500 to-pink-500 rounded-xl flex items-center justify-center mb-6">
<i data-feather="activity" class="w-8 h-8 text-white"></i>
</div>
<h3 class="font-bold text-xl mb-3 text-white">Real-Time Voice Cloning</h3>
<p class="text-gray-300 leading-relaxed">Leveraging the state-of-the-art Real-Time Voice Cloning model for instant, high-quality voice synthesis</p>
</div>
<div class="feature-card p-8 rounded-xl">
<div class="w-16 h-16 bg-gradient-to-br from-pink-500 to-red-500 rounded-xl flex items-center justify-center mb-6">
<i data-feather="cpu" class="w-8 h-8 text-white"></i>
</div>
<h3 class="font-bold text-xl mb-3 text-white">Fine-Tuned TTS</h3>
<p class="text-gray-300 leading-relaxed">Custom fine-tuned Text-to-Speech models for natural intonation and emotional expression</p>
</div>
</div>
</section>
<section class="w-full max-w-6xl glass-card p-12 mb-12">
<h2 class="text-3xl font-bold gradient-text mb-8 text-center">Advanced Voice Cloning Features</h2>
<div class="grid lg:grid-cols-3 gap-8">
<div class="feature-card p-8 rounded-xl">
<div class="w-16 h-16 bg-gradient-to-br from-indigo-500 to-purple-500 rounded-xl flex items-center justify-center mb-6">
<i data-feather="layers" class="w-8 h-8 text-white"></i>
</div>
<h3 class="font-bold text-xl mb-3 text-white">Multi-Speaker Support</h3>
<p class="text-gray-300 leading-relaxed">Train and manage multiple voice models simultaneously with advanced speaker separation technology</p>
</div>
<div class="feature-card p-8 rounded-xl">
<div class="w-16 h-16 bg-gradient-to-br from-purple-500 to-pink-500 rounded-xl flex items-center justify-center mb-6">
<i data-feather="settings" class="w-8 h-8 text-white"></i>
</div>
<h3 class="font-bold text-xl mb-3 text-white">Advanced Fine-Tuning</h3>
<p class="text-gray-300 leading-relaxed">Precise control over pitch, emotion, speed, and tone with real-time preview and adjustment</p>
</div>
<div class="feature-card p-8 rounded-xl">
<div class="w-16 h-16 bg-gradient-to-br from-pink-500 to-red-500 rounded-xl flex items-center justify-center mb-6">
<i data-feather="cloud" class="w-8 h-8 text-white"></i>
</div>
<h3 class="font-bold text-xl mb-3 text-white">Enterprise API</h3>
<p class="text-gray-300 leading-relaxed">Seamless integration with your applications through our powerful and scalable API infrastructure</p>
</div>
</div>
</section>
<footer class="w-full max-w-6xl py-8 text-center">
<div class="flex items-center justify-center space-x-6 mb-4">
<a href="index.html" class="w-10 h-10 bg-indigo-500 rounded-full flex items-center justify-center transition-all duration-300">
<i data-feather="home" class="w-5 h-5 text-white"></i>
</a>
<a href="voice-clone.html" class="w-10 h-10 bg-gray-800 rounded-full flex items-center justify-center hover:bg-purple-500 transition-all duration-300">
<i data-feather="copy" class="w-5 h-5 text-gray-300"></i>
</a>
</div>
<p class="text-gray-400 text-sm">© 2024 VoiceCloneAI - Advanced Voice Cloning Technology</p>
<div class="mt-4 audio-wave w-24 mx-auto"></div>
</footer>
</div>
<script>
feather.replace();
// Initialize Vanta.js waves background
VANTA.WAVES({
el: "#wave-bg",
color: 0x6366f1,
waveHeight: 20,
shininess: 80,
waveSpeed: 0.5,
zoom: 0.8,
colorDark: 0x0f0f23,
colorLight: 0x6366f1
});
// Add font
const link = document.createElement('link');
link.href = 'https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap';
link.rel = 'stylesheet';
document.head.appendChild(link);
// Advanced AI Model Integration (ElevenLabs-like)
class VoiceCloneAI {
constructor() {
this.whisperApiKey = 'YOUR_OPENAI_API_KEY'; // Replace with actual API key
this.elevenLabsApiKey = 'YOUR_ELEVENLABS_API_KEY'; // Replace with actual API key
this.voiceCloneEndpoint = 'https://api.elevenlabs.io/v1/voice-clone';
this.textToSpeechEndpoint = 'https://api.elevenlabs.io/v1/text-to-speech';
}
async transcribeWithWhisper(audioBlob) {
const formData = new FormData();
formData.append('file', audioBlob, 'audio.wav');
formData.append('model', 'whisper-1');
try {
const response = await fetch('https://api.openai.com/v1/audio/transcriptions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.whisperApiKey}`,
},
body: formData
});
const data = await response.json();
return data.text;
} catch (error) {
console.error('Whisper transcription error:', error);
// Fallback: return placeholder text for demo
return "This is a demo transcription of your audio file. In a real implementation, this would be the actual text from your audio.";
}
}
async cloneVoice(audioBlob, text) {
// ElevenLabs voice cloning simulation
const formData = new FormData();
formData.append('files', audioBlob);
formData.append('name', 'cloned-voice');
formData.append('description', 'Voice clone created from uploaded audio');
try {
const response = await fetch(this.voiceCloneEndpoint, {
method: 'POST',
headers: {
'xi-api-key': this.elevenLabsApiKey,
},
body: formData
});
if (!response.ok) throw new Error('Voice cloning failed');
const data = await response.json();
return data; // Returns voice ID and metadata
} catch (error) {
console.error('Voice cloning error:', error);
// Fallback: return mock data for demo
return {
voice_id: 'demo_voice_' + Date.now(),
status: 'success'
};
}
}
async generateVoice(text, voiceSettings = {}) {
// ElevenLabs-like text-to-speech with voice cloning
try {
// For demo purposes, we'll simulate the API call
// In a real implementation, you would use:
// const response = await fetch(`${this.textToSpeechEndpoint}/${voiceId}`, {
// method: 'POST',
// headers: {
// 'xi-api-key': this.elevenLabsApiKey,
// 'Content-Type': 'application/json',
// },
// body: JSON.stringify({
// text: text,
// model_id: "eleven_monolingual_v1",
// voice_settings: {
// stability: voiceSettings.stability || 0.7,
// similarity_boost: voiceSettings.similarity_boost || 0.8,
// speed: voiceSettings.speed || 1.0
// }
// })
// });
// Simulate API delay
await new Promise(resolve => setTimeout(resolve, 2000));
// Create a mock audio blob for demo
// In real implementation, you would return response.blob()
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
const oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioContext.destination);
oscillator.frequency.value = 440;
oscillator.type = 'sine';
gainNode.gain.setValueAtTime(0, audioContext.currentTime);
gainNode.gain.linearRampToValueAtTime(0.1, audioContext.currentTime + 0.1);
const duration = Math.min(text.length * 0.1, 5); // Max 5 seconds for demo
oscillator.start(audioContext.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.001, audioContext.currentTime + duration);
oscillator.stop(audioContext.currentTime + duration);
// For demo, we'll return a placeholder
// In real implementation, return the actual audio blob from API
return new Blob([], { type: 'audio/mpeg' });
} catch (error) {
console.error('TTS generation error:', error);
throw new Error('TTS generation failed');
}
}
// Additional ElevenLabs-like functionality
async getVoiceSettings(voiceId) {
// Get current voice settings
try {
const response = await fetch(`https://api.elevenlabs.io/v1/voices/${voiceId}/settings`, {
headers: {
'xi-api-key': this.elevenLabsApiKey,
}
});
return await response.json();
} catch (error) {
console.error('Error getting voice settings:', error);
return {
stability: 0.7,
similarity_boost: 0.8,
speed: 1.0
};
}
}
async updateVoiceSettings(voiceId, settings) {
// Update voice settings like ElevenLabs
try {
const response = await fetch(`https://api.elevenlabs.io/v1/voices/${voiceId}/settings`, {
method: 'POST',
headers: {
'xi-api-key': this.elevenLabsApiKey,
'Content-Type': 'application/json',
},
body: JSON.stringify(settings)
});
return await response.json();
} catch (error) {
console.error('Error updating voice settings:', error);
return { status: 'demo_mode' };
}
}
}
// Initialize AI Model
const voiceAI = new VoiceCloneAI();
// Recording and Upload
const recordBtn = document.getElementById('recordBtn');
const voiceUpload = document.getElementById('voiceUpload');
voiceUpload.addEventListener('change', async (e) => {
const file = e.target.files[0];
if (!file) return;
if (!file.type.match('audio.*')) {
alert('Please select an audio file');
return;
}
if (file.size > 50 * 1024 * 1024) {
alert('File size exceeds 50MB limit');
return;
}
// Process with advanced AI
recordingStatus.textContent = 'Processing with Whisper AI...';
recordBtn.classList.add('recording');
try {
// Transcribe audio using Whisper
const transcription = await voiceAI.transcribeWithWhisper(file);
// Update UI with transcription
document.getElementById('textToGenerate').value = transcription;
stopRecording();
updateVoicePreview();
// Enhanced success notification
const successNotification = document.createElement('div');
successNotification.className = 'fixed top-4 right-4 bg-gradient-to-r from-green-500 to-blue-500 text-white px-6 py-3 rounded-xl shadow-2xl z-50';
successNotification.innerHTML = '✅ Audio processed with Whisper AI!';
document.body.appendChild(successNotification);
setTimeout(() => {
successNotification.remove();
}, 3000);
} catch (error) {
alert('Error processing audio: ' + error.message);
stopRecording();
}
});
const recordingStatus = document.getElementById('recordingStatus');
const soundWave = document.getElementById('soundWave');
let isRecording = false;
let progress = 0;
let interval;
recordBtn.addEventListener('click', () => {
isRecording = !isRecording;
if (isRecording) {
recordBtn.classList.add('recording');
recordingStatus.textContent = '🎤 Recording... Speak now';
recordingStatus.className = 'absolute -bottom-8 left-0 right-0 text-center text-sm text-indigo-400 font-medium';
// Enhanced sound wave animation
interval = setInterval(() => {
progress += Math.random() * 3;
if (progress > 100) progress = 0;
soundWave.style.width = `${progress}%`;
soundWave.style.opacity = `${0.3 + (progress / 100) * 0.7}`;
}, 100);
// After 5 seconds, stop recording
setTimeout(() => {
stopRecording();
updateVoicePreview();
}, 5000);
} else {
stopRecording();
}
});
function stopRecording() {
isRecording = false;
recordBtn.classList.remove('recording');
recordingStatus.textContent = 'Click to record';
recordingStatus.className = 'absolute -bottom-8 left-0 right-0 text-center text-sm text-gray-400';
clearInterval(interval);
soundWave.style.width = '0%';
soundWave.style.opacity = '1';
}
function updateVoicePreview() {
const voicePreview = document.getElementById('voicePreview');
const voiceParams = document.getElementById('voiceParams');
voicePreview.innerHTML = `
<div class="flex flex-col items-center justify-center">
<div class="relative mb-4">
<img src="http://static.photos/technology/120x120/42" class="w-24 h-24 rounded-full object-cover border-4 border-indigo-400 shadow-lg">
<div class="absolute -bottom-2 -right-2 bg-gradient-to-br from-indigo-500 to-pink-500 text-white rounded-full p-2 shadow-lg">
<i data-feather="check" class="w-4 h-4"></i>
</div>
</div>
<p class="text-center text-indigo-300 font-medium mb-4">Voice model trained successfully! 🎉</p>
<div class="audio-wave w-32 mb-4"></div>
</div>
<div class="w-full mb-6">
<textarea id="textToGenerate" class="w-full p-4 bg-gray-700 border border-indigo-400 rounded-xl resize-none focus:ring-2 focus:ring-indigo-500 text-white placeholder-gray-400" rows="3" placeholder="Try: 'Hello, this is my AI voice clone! I can read any text you provide, just like ElevenLabs.'"></textarea>
</div>
<div class="w-full bg-gray-900 rounded-xl p-4 mb-4">
<h3 class="text-lg font-semibold text-white mb-3">Text-to-Speech Preview</h3>
<div class="space-y-3">
<div class="flex items-center justify-between">
<span class="text-gray-300">Ready to read your text</span>
<button id="previewPlayBtn" class="px-4 py-2 bg-indigo-600 text-white rounded-lg flex items-center space-x-2 hover:bg-indigo-700 transition-colors">
<i data-feather="play" class="w-4 h-4"></i>
<span>Play</span>
</button>
</div>
<div class="flex items-center space-x-4">
<span class="text-gray-400 text-sm">Progress:</span>
<div class="flex-1 bg-gray-700 rounded-full h-2">
<div id="playbackProgress" class="bg-gradient-to-r from-indigo-500 to-pink-500 h-2 rounded-full w-0 transition-all duration-300"></div>
</div>
</div>
</div>
</div>
`;
voiceParams.classList.remove('hidden');
feather.replace();
// Add floating animation to the success image
const successImage = voicePreview.querySelector('img');
if (successImage) {
successImage.classList.add('floating');
}
// Add ElevenLabs-like text reading functionality
const previewPlayBtn = document.getElementById('previewPlayBtn');
const playbackProgress = document.getElementById('playbackProgress');
const textToGenerate = document.getElementById('textToGenerate');
previewPlayBtn.addEventListener('click', async () => {
const text = textToGenerate.value.trim();
if (!text) {
// Show error notification
const errorNotification = document.createElement('div');
errorNotification.className = 'fixed top-4 right-4 bg-gradient-to-r from-red-500 to-pink-500 text-white px-6 py-3 rounded-xl shadow-2xl z-50';
errorNotification.innerHTML = '⚠️ Please enter text to read';
document.body.appendChild(errorNotification);
setTimeout(() => errorNotification.remove(), 3000);
return;
}
// Update button state
previewPlayBtn.disabled = true;
previewPlayBtn.innerHTML = '<i data-feather="loader" class="w-4 h-4 animate-spin"></i><span>Generating...</span>';
feather.replace();
try {
// Simulate ElevenLabs-like text reading
const audioBlob = await voiceAI.generateVoice(text, {
voice_settings: {
stability: 0.7,
similarity_boost: 0.8,
speed: 1.0
}
});
// Create audio element
const audioUrl = URL.createObjectURL(audioBlob);
const audio = new Audio(audioUrl);
// Update button to show playing state
previewPlayBtn.innerHTML = '<i data-feather="pause" class="w-4 h-4"></i><span>Playing...</span>';
feather.replace();
// Handle playback progress
audio.addEventListener('timeupdate', () => {
const progress = (audio.currentTime / audio.duration) * 100;
playbackProgress.style.width = `${progress}%`;
});
audio.addEventListener('ended', () => {
previewPlayBtn.disabled = false;
previewPlayBtn.innerHTML = '<i data-feather="play" class="w-4 h-4"></i><span>Play</span>';
playbackProgress.style.width = '0%';
feather.replace();
});
audio.addEventListener('pause', () => {
previewPlayBtn.disabled = false;
previewPlayBtn.innerHTML = '<i data-feather="play" class="w-4 h-4"></i><span>Play</span>';
feather.replace();
});
// Play audio
await audio.play();
// Add pause functionality
previewPlayBtn.onclick = () => {
if (audio.paused) {
audio.play();
previewPlayBtn.innerHTML = '<i data-feather="pause" class="w-4 h-4"></i><span>Playing...</span>';
} else {
audio.pause();
previewPlayBtn.innerHTML = '<i data-feather="play" class="w-4 h-4"></i><span>Play</span>';
}
feather.replace();
};
} catch (error) {
console.error('Playback error:', error);
previewPlayBtn.disabled = false;
previewPlayBtn.innerHTML = '<i data-feather="play" class="w-4 h-4"></i><span>Play</span>';
feather.replace();
// Show error notification
const errorNotification = document.createElement('div');
errorNotification.className = 'fixed top-4 right-4 bg-gradient-to-r from-red-500 to-pink-500 text-white px-6 py-3 rounded-xl shadow-2xl z-50';
errorNotification.innerHTML = '❌ Error generating audio';
document.body.appendChild(errorNotification);
setTimeout(() => errorNotification.remove(), 3000);
}
});
}
// Add event listeners for new buttons
document.getElementById('trainBtn').addEventListener('click', () => {
const recordingStatus = document.getElementById('recordingStatus');
recordingStatus.textContent = '🤖 Training AI model...';
recordingStatus.className = 'absolute -bottom-8 left-0 right-0 text-center text-sm text-purple-400 font-medium';
recordBtn.classList.add('recording');
// Enhanced training simulation
setTimeout(() => {
stopRecording();
updateVoicePreview();
// Show success notification
const notification = document.createElement('div');
notification.className = 'fixed top-4 right-4 bg-gradient-to-r from-green-500 to-blue-500 text-white px-6 py-3 rounded-xl shadow-2xl z-50';
notification.innerHTML = '🎯 Voice model trained successfully!';
document.body.appendChild(notification);
setTimeout(() => {
notification.remove();
}, 3000);
}, 5000);
});
document.getElementById('generateBtn').addEventListener('click', async () => {
const text = document.getElementById('textToGenerate').value.trim();
if (!text) {
// Enhanced error notification
const errorNotification = document.createElement('div');
errorNotification.className = 'fixed top-4 right-4 bg-gradient-to-r from-red-500 to-pink-500 text-white px-6 py-3 rounded-xl shadow-2xl z-50';
errorNotification.innerHTML = '⚠️ Please enter some text to generate';
document.body.appendChild(errorNotification);
setTimeout(() => {
errorNotification.remove();
}, 3000);
return;
}
// Enhanced AI generation notification
const generatingNotification = document.createElement('div');
generatingNotification.className = 'fixed top-4 right-4 bg-gradient-to-r from-indigo-500 to-purple-500 text-white px-6 py-3 rounded-xl shadow-2xl z-50';
generatingNotification.innerHTML = `🤖 Generating with AI: "${text.substring(0, 30)}${text.length > 30 ? '...' : ''}"`;
document.body.appendChild(generatingNotification);
try {
// Get voice settings from sliders
const similarity = document.querySelector('input[type="range"]:nth-child(1)').value;
const emotion = document.querySelector('input[type="range"]:nth-child(2)').value;
const speed = document.querySelector('input[type="range"]:nth-child(3)').value;
// Generate voice with advanced AI (ElevenLabs-like)
const audioBlob = await voiceAI.generateVoice(text, {
voice_settings: {
stability: similarity / 100,
similarity_boost: emotion / 100,
speed: speed / 100
}
});
// Create audio element and play
const audioUrl = URL.createObjectURL(audioBlob);
const audio = new Audio(audioUrl);
// Add download functionality
const downloadBtn = document.getElementById('downloadBtn');
const originalOnClick = downloadBtn.onclick;
downloadBtn.onclick = () => {
const a = document.createElement('a');
a.href = audioUrl;
a.download = `voice-clone-${Date.now()}.mp3`;
a.click();
// Show download success notification
const downloadNotification = document.createElement('div');
downloadNotification.className = 'fixed top-4 right-4 bg-gradient-to-r from-green-500 to-blue-500 text-white px-6 py-3 rounded-xl shadow-2xl z-50';
downloadNotification.innerHTML = '✅ Audio downloaded!';
document.body.appendChild(downloadNotification);
setTimeout(() => downloadNotification.remove(), 3000);
};
// Play the audio
await audio.play();
generatingNotification.innerHTML = '✅ AI Voice generated successfully! Playing now...';
setTimeout(() => {
generatingNotification.remove();
}, 3000);
} catch (error) {
generatingNotification.innerHTML = '❌ AI Generation failed';
generatingNotification.className = 'fixed top-4 right-4 bg-gradient-to-r from-red-500 to-pink-500 text-white px-6 py-3 rounded-xl shadow-2xl z-50';
setTimeout(() => {
generatingNotification.remove();
}, 3000);
console.error('Generation error:', error);
}
});
document.getElementById('downloadBtn').addEventListener('click', () => {
// Enhanced download notification
const downloadNotification = document.createElement('div');
downloadNotification.className = 'fixed top-4 right-4 bg-gradient-to-r from-yellow-500 to-orange-500 text-white px-6 py-3 rounded-xl shadow-2xl z-50';
downloadNotification.innerHTML = '📥 Downloading voice model...';
document.body.appendChild(downloadNotification);
setTimeout(() => {
downloadNotification.innerHTML = '✅ Download complete!';
setTimeout(() => {
downloadNotification.remove();
}, 2000);
}, 2000);
});
</script>
<script>
// Initialize advanced AI models
async function initAIModels() {
try {
// Check if Web Audio API is supported
if (!window.AudioContext && !window.webkitAudioContext) {
console.warn('Web Audio API not supported');
return;
}
// Initialize audio context for advanced processing
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
console.log('Advanced AI models initialized with Web Audio API');
// Additional model initialization can go here
} catch (error) {
console.error('Error initializing AI models:', error);
}
}
// Initialize when page loads
document.addEventListener('DOMContentLoaded', () => {
initAIModels();
});
</script>
</body>
</html>