i2v / index.html
deepnd's picture
Add 2 files
7eb9394 verified
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ImageToVideo - Transformez vos images en vidéos parlantes</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>
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.animate-pulse {
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
.video-preview {
background: linear-gradient(145deg, #f0f0f0, #ffffff);
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
}
.voice-option:hover {
transform: scale(1.03);
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1);
}
.voice-option.selected {
border-color: #6366f1;
background-color: #eef2ff;
}
.dropzone {
border: 2px dashed #cbd5e1;
transition: all 0.3s ease;
}
.dropzone.active {
border-color: #6366f1;
background-color: #eef2ff;
}
#generatedVideo {
transition: opacity 0.5s ease;
}
.progress-bar {
height: 6px;
transition: width 0.3s ease;
}
</style>
</head>
<body class="bg-gray-50 min-h-screen">
<div class="container mx-auto px-4 py-8 max-w-6xl">
<!-- Header -->
<header class="mb-10 text-center">
<h1 class="text-4xl font-bold text-indigo-700 mb-2">ImageToVideo</h1>
<p class="text-lg text-gray-600">Transformez vos images en vidéos parlantes avec animations réalistes</p>
</header>
<!-- Main App -->
<div class="bg-white rounded-xl shadow-lg overflow-hidden">
<!-- Progress Steps -->
<div class="flex justify-between px-8 py-4 bg-gray-50 border-b">
<div class="step flex-1 text-center relative">
<div class="w-10 h-10 mx-auto rounded-full bg-indigo-600 text-white flex items-center justify-center font-bold">1</div>
<p class="mt-2 text-sm font-medium text-indigo-600">Image & Prompt</p>
</div>
<div class="step flex-1 text-center relative">
<div class="w-10 h-10 mx-auto rounded-full bg-gray-200 text-gray-600 flex items-center justify-center font-bold">2</div>
<p class="mt-2 text-sm font-medium text-gray-500">Paramètres vidéo</p>
</div>
<div class="step flex-1 text-center relative">
<div class="w-10 h-10 mx-auto rounded-full bg-gray-200 text-gray-600 flex items-center justify-center font-bold">3</div>
<p class="mt-2 text-sm font-medium text-gray-500">Voix & Texte</p>
</div>
<div class="step flex-1 text-center relative">
<div class="w-10 h-10 mx-auto rounded-full bg-gray-200 text-gray-600 flex items-center justify-center font-bold">4</div>
<p class="mt-2 text-sm font-medium text-gray-500">Génération</p>
</div>
</div>
<!-- Content Area -->
<div class="p-8">
<!-- Step 1: Image Upload & Prompt -->
<div id="step1" class="step-content">
<div class="grid md:grid-cols-2 gap-8">
<!-- Image Upload -->
<div>
<h2 class="text-xl font-semibold mb-4 text-gray-800">1. Téléversez votre image</h2>
<div id="dropzone" class="dropzone rounded-lg p-8 text-center cursor-pointer">
<div class="flex flex-col items-center justify-center">
<i class="fas fa-cloud-upload-alt text-4xl text-indigo-500 mb-3"></i>
<p class="text-gray-600 mb-2">Glissez-déposez votre image ici</p>
<p class="text-sm text-gray-500 mb-4">ou</p>
<button id="uploadBtn" class="bg-indigo-600 hover:bg-indigo-700 text-white px-6 py-2 rounded-lg transition duration-200">
Sélectionner un fichier
</button>
<input type="file" id="fileInput" class="hidden" accept="image/*">
</div>
</div>
<div id="imagePreviewContainer" class="mt-4 hidden">
<div class="relative">
<img id="imagePreview" src="" alt="Preview" class="w-full h-auto rounded-lg border border-gray-200">
<button id="removeImage" class="absolute top-2 right-2 bg-red-500 text-white rounded-full p-2 hover:bg-red-600 transition">
<i class="fas fa-times"></i>
</button>
</div>
</div>
</div>
<!-- Prompt Input -->
<div>
<h2 class="text-xl font-semibold mb-4 text-gray-800">2. Décrivez votre vidéo</h2>
<div class="mb-4">
<label for="prompt" class="block text-sm font-medium text-gray-700 mb-2">Prompt de description</label>
<textarea id="prompt" rows="4" class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-indigo-500 focus:border-indigo-500" placeholder="Décrivez le style de la vidéo que vous souhaitez créer (ex: 'Un personnage souriant qui parle avec enthousiasme dans un environnement professionnel')"></textarea>
</div>
<div class="flex justify-end">
<button id="nextStep1" class="bg-indigo-600 hover:bg-indigo-700 text-white px-6 py-2 rounded-lg transition duration-200 disabled:opacity-50 disabled:cursor-not-allowed" disabled>
Suivant <i class="fas fa-arrow-right ml-2"></i>
</button>
</div>
</div>
</div>
</div>
<!-- Step 2: Video Settings -->
<div id="step2" class="step-content hidden">
<h2 class="text-xl font-semibold mb-6 text-gray-800">Paramètres de la vidéo</h2>
<div class="grid md:grid-cols-2 gap-8">
<!-- Duration -->
<div>
<label for="duration" class="block text-sm font-medium text-gray-700 mb-2">Durée de la vidéo (secondes)</label>
<input type="range" id="duration" min="5" max="60" value="15" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer">
<div class="flex justify-between mt-2">
<span class="text-sm text-gray-500">5s</span>
<span id="durationValue" class="font-medium">15s</span>
<span class="text-sm text-gray-500">60s</span>
</div>
</div>
<!-- Style -->
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Style d'animation</label>
<div class="grid grid-cols-2 gap-3">
<button class="style-option border rounded-lg p-3 hover:bg-gray-50 transition" data-style="realistic">
<i class="fas fa-user text-indigo-500 mr-2"></i> Réaliste
</button>
<button class="style-option border rounded-lg p-3 hover:bg-gray-50 transition" data-style="cartoon">
<i class="fas fa-paint-brush text-indigo-500 mr-2"></i> Dessin animé
</button>
<button class="style-option border rounded-lg p-3 hover:bg-gray-50 transition" data-style="anime">
<i class="fas fa-moon text-indigo-500 mr-2"></i> Anime
</button>
<button class="style-option border rounded-lg p-3 hover:bg-gray-50 transition" data-style="pixel">
<i class="fas fa-gamepad text-indigo-500 mr-2"></i> Pixel Art
</button>
</div>
</div>
</div>
<div class="flex justify-between mt-8">
<button id="prevStep2" class="text-gray-600 hover:text-gray-800 px-6 py-2 rounded-lg transition duration-200 border border-gray-300">
<i class="fas fa-arrow-left mr-2"></i> Retour
</button>
<button id="nextStep2" class="bg-indigo-600 hover:bg-indigo-700 text-white px-6 py-2 rounded-lg transition duration-200">
Suivant <i class="fas fa-arrow-right ml-2"></i>
</button>
</div>
</div>
<!-- Step 3: Voice & Text -->
<div id="step3" class="step-content hidden">
<h2 class="text-xl font-semibold mb-6 text-gray-800">Voix et texte</h2>
<div class="grid md:grid-cols-2 gap-8">
<!-- Voice Selection -->
<div>
<label class="block text-sm font-medium text-gray-700 mb-3">Sélectionnez une voix</label>
<div class="grid grid-cols-1 gap-3">
<!-- Female Voices -->
<div class="mb-4">
<h3 class="text-sm font-medium text-gray-500 mb-2">Voix féminines</h3>
<div class="grid grid-cols-2 gap-3">
<div class="voice-option border rounded-lg p-3 cursor-pointer transition" data-voice="french-female-1" data-gender="female">
<div class="flex items-center">
<div class="w-10 h-10 rounded-full bg-pink-100 flex items-center justify-center mr-3">
<i class="fas fa-female text-pink-500"></i>
</div>
<div>
<p class="font-medium">Sophie</p>
<p class="text-xs text-gray-500">Ton chaleureux</p>
</div>
</div>
</div>
<div class="voice-option border rounded-lg p-3 cursor-pointer transition" data-voice="french-female-2" data-gender="female">
<div class="flex items-center">
<div class="w-10 h-10 rounded-full bg-pink-100 flex items-center justify-center mr-3">
<i class="fas fa-female text-pink-500"></i>
</div>
<div>
<p class="font-medium">Camille</p>
<p class="text-xs text-gray-500">Ton professionnel</p>
</div>
</div>
</div>
</div>
</div>
<!-- Male Voices -->
<div>
<h3 class="text-sm font-medium text-gray-500 mb-2">Voix masculines</h3>
<div class="grid grid-cols-2 gap-3">
<div class="voice-option border rounded-lg p-3 cursor-pointer transition" data-voice="french-male-1" data-gender="male">
<div class="flex items-center">
<div class="w-10 h-10 rounded-full bg-blue-100 flex items-center justify-center mr-3">
<i class="fas fa-male text-blue-500"></i>
</div>
<div>
<p class="font-medium">Thomas</p>
<p class="text-xs text-gray-500">Ton amical</p>
</div>
</div>
</div>
<div class="voice-option border rounded-lg p-3 cursor-pointer transition" data-voice="french-male-2" data-gender="male">
<div class="flex items-center">
<div class="w-10 h-10 rounded-full bg-blue-100 flex items-center justify-center mr-3">
<i class="fas fa-male text-blue-500"></i>
</div>
<div>
<p class="font-medium">Pierre</p>
<p class="text-xs text-gray-500">Ton autoritaire</p>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Voice Preview -->
<div id="voicePreviewContainer" class="mt-6 hidden">
<div class="flex items-center justify-between bg-gray-50 p-4 rounded-lg">
<div class="flex items-center">
<div id="voiceIcon" class="w-10 h-10 rounded-full flex items-center justify-center mr-3">
<i id="voiceGenderIcon" class="fas"></i>
</div>
<div>
<p id="voiceName" class="font-medium"></p>
<p id="voiceDesc" class="text-xs text-gray-500"></p>
</div>
</div>
<button id="playVoicePreview" class="bg-indigo-100 text-indigo-600 p-2 rounded-full hover:bg-indigo-200 transition">
<i class="fas fa-play"></i>
</button>
</div>
</div>
</div>
<!-- Text Input -->
<div>
<label for="speechText" class="block text-sm font-medium text-gray-700 mb-2">Texte à prononcer</label>
<textarea id="speechText" rows="8" class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-indigo-500 focus:border-indigo-500" placeholder="Entrez le texte que la vidéo doit prononcer..."></textarea>
<div class="mt-2 flex justify-between items-center">
<span id="charCount" class="text-sm text-gray-500">0 caractères</span>
<button id="textToSpeechPreview" class="text-indigo-600 hover:text-indigo-800 text-sm font-medium flex items-center">
<i class="fas fa-headphones mr-1"></i> Pré-écouter
</button>
</div>
</div>
</div>
<div class="flex justify-between mt-8">
<button id="prevStep3" class="text-gray-600 hover:text-gray-800 px-6 py-2 rounded-lg transition duration-200 border border-gray-300">
<i class="fas fa-arrow-left mr-2"></i> Retour
</button>
<button id="nextStep3" class="bg-indigo-600 hover:bg-indigo-700 text-white px-6 py-2 rounded-lg transition duration-200 disabled:opacity-50 disabled:cursor-not-allowed" disabled>
Suivant <i class="fas fa-arrow-right ml-2"></i>
</button>
</div>
</div>
<!-- Step 4: Generation -->
<div id="step4" class="step-content hidden">
<h2 class="text-xl font-semibold mb-6 text-gray-800">Génération de la vidéo</h2>
<div class="grid md:grid-cols-2 gap-8">
<!-- Settings Summary -->
<div>
<div class="bg-gray-50 p-6 rounded-lg">
<h3 class="font-medium text-lg mb-4">Récapitulatif</h3>
<div class="space-y-4">
<div>
<p class="text-sm text-gray-500">Image source</p>
<div class="flex items-center mt-1">
<img id="summaryImage" src="" alt="Summary" class="w-12 h-12 rounded object-cover mr-3">
<span id="summaryImageName" class="text-sm font-medium"></span>
</div>
</div>
<div>
<p class="text-sm text-gray-500">Prompt</p>
<p id="summaryPrompt" class="text-sm font-medium mt-1"></p>
</div>
<div class="grid grid-cols-2 gap-4">
<div>
<p class="text-sm text-gray-500">Durée</p>
<p id="summaryDuration" class="text-sm font-medium mt-1"></p>
</div>
<div>
<p class="text-sm text-gray-500">Style</p>
<p id="summaryStyle" class="text-sm font-medium mt-1"></p>
</div>
</div>
<div>
<p class="text-sm text-gray-500">Voix</p>
<div class="flex items-center mt-1">
<div id="summaryVoiceIcon" class="w-8 h-8 rounded-full flex items-center justify-center mr-2">
<i id="summaryVoiceGenderIcon" class="fas text-xs"></i>
</div>
<p id="summaryVoice" class="text-sm font-medium"></p>
</div>
</div>
<div>
<p class="text-sm text-gray-500">Texte</p>
<p id="summaryText" class="text-sm font-medium mt-1 line-clamp-3"></p>
</div>
</div>
</div>
<button id="generateBtn" class="w-full mt-6 bg-indigo-600 hover:bg-indigo-700 text-white px-6 py-3 rounded-lg transition duration-200 font-medium flex items-center justify-center">
<i class="fas fa-magic mr-2"></i> Générer la vidéo
</button>
</div>
<!-- Generation Preview -->
<div>
<div class="video-preview rounded-lg p-4 flex flex-col items-center justify-center h-full">
<div id="generationStatus" class="text-center">
<i class="fas fa-video text-4xl text-indigo-500 mb-4"></i>
<h3 class="text-xl font-medium mb-2">Prêt à générer</h3>
<p class="text-gray-600 mb-6">Cliquez sur le bouton "Générer la vidéo" pour commencer le processus.</p>
</div>
<!-- Progress Bar -->
<div id="progressContainer" class="w-full bg-gray-200 rounded-full h-2.5 mb-4 hidden">
<div id="progressBar" class="progress-bar bg-indigo-600 rounded-full" style="width: 0%"></div>
</div>
<p id="progressText" class="text-sm text-gray-500 mb-6 hidden">Préparation des données...</p>
<!-- Generated Video -->
<video id="generatedVideo" controls class="w-full rounded-lg hidden"></video>
<!-- Download Button -->
<div id="downloadSection" class="mt-4 hidden">
<button id="downloadBtn" class="bg-green-600 hover:bg-green-700 text-white px-6 py-2 rounded-lg transition duration-200">
<i class="fas fa-download mr-2"></i> Télécharger la vidéo
</button>
</div>
</div>
</div>
</div>
<div class="flex justify-start mt-8">
<button id="prevStep4" class="text-gray-600 hover:text-gray-800 px-6 py-2 rounded-lg transition duration-200 border border-gray-300">
<i class="fas fa-arrow-left mr-2"></i> Retour
</button>
</div>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// DOM Elements
const stepContents = document.querySelectorAll('.step-content');
const steps = document.querySelectorAll('.step');
const uploadBtn = document.getElementById('uploadBtn');
const fileInput = document.getElementById('fileInput');
const dropzone = document.getElementById('dropzone');
const imagePreviewContainer = document.getElementById('imagePreviewContainer');
const imagePreview = document.getElementById('imagePreview');
const removeImage = document.getElementById('removeImage');
const nextStep1 = document.getElementById('nextStep1');
const prevStep2 = document.getElementById('prevStep2');
const nextStep2 = document.getElementById('nextStep2');
const prevStep3 = document.getElementById('prevStep3');
const nextStep3 = document.getElementById('nextStep3');
const prevStep4 = document.getElementById('prevStep4');
const duration = document.getElementById('duration');
const durationValue = document.getElementById('durationValue');
const styleOptions = document.querySelectorAll('.style-option');
const voiceOptions = document.querySelectorAll('.voice-option');
const voicePreviewContainer = document.getElementById('voicePreviewContainer');
const voiceName = document.getElementById('voiceName');
const voiceDesc = document.getElementById('voiceDesc');
const voiceGenderIcon = document.getElementById('voiceGenderIcon');
const voiceIcon = document.getElementById('voiceIcon');
const speechText = document.getElementById('speechText');
const charCount = document.getElementById('charCount');
const generateBtn = document.getElementById('generateBtn');
const progressContainer = document.getElementById('progressContainer');
const progressBar = document.getElementById('progressBar');
const progressText = document.getElementById('progressText');
const generatedVideo = document.getElementById('generatedVideo');
const downloadSection = document.getElementById('downloadSection');
const downloadBtn = document.getElementById('downloadBtn');
const generationStatus = document.getElementById('generationStatus');
const textToSpeechPreview = document.getElementById('textToSpeechPreview');
const playVoicePreview = document.getElementById('playVoicePreview');
// Summary elements
const summaryImage = document.getElementById('summaryImage');
const summaryImageName = document.getElementById('summaryImageName');
const summaryPrompt = document.getElementById('summaryPrompt');
const summaryDuration = document.getElementById('summaryDuration');
const summaryStyle = document.getElementById('summaryStyle');
const summaryVoice = document.getElementById('summaryVoice');
const summaryVoiceIcon = document.getElementById('summaryVoiceIcon');
const summaryVoiceGenderIcon = document.getElementById('summaryVoiceGenderIcon');
const summaryText = document.getElementById('summaryText');
// App State
let currentStep = 1;
let selectedImage = null;
let selectedStyle = 'realistic';
let selectedVoice = null;
let audioContext = null;
// Initialize
updateStepIndicator();
// Event Listeners
uploadBtn.addEventListener('click', () => fileInput.click());
fileInput.addEventListener('change', handleFileSelect);
dropzone.addEventListener('dragover', (e) => {
e.preventDefault();
dropzone.classList.add('active');
});
dropzone.addEventListener('dragleave', () => {
dropzone.classList.remove('active');
});
dropzone.addEventListener('drop', (e) => {
e.preventDefault();
dropzone.classList.remove('active');
if (e.dataTransfer.files.length) {
fileInput.files = e.dataTransfer.files;
handleFileSelect({ target: fileInput });
}
});
removeImage.addEventListener('click', () => {
selectedImage = null;
imagePreviewContainer.classList.add('hidden');
fileInput.value = '';
nextStep1.disabled = true;
});
nextStep1.addEventListener('click', () => navigateToStep(2));
prevStep2.addEventListener('click', () => navigateToStep(1));
nextStep2.addEventListener('click', () => navigateToStep(3));
prevStep3.addEventListener('click', () => navigateToStep(2));
nextStep3.addEventListener('click', () => navigateToStep(4));
prevStep4.addEventListener('click', () => navigateToStep(3));
duration.addEventListener('input', () => {
durationValue.textContent = `${duration.value}s`;
});
styleOptions.forEach(option => {
option.addEventListener('click', () => {
styleOptions.forEach(opt => opt.classList.remove('bg-indigo-50', 'border-indigo-300'));
option.classList.add('bg-indigo-50', 'border-indigo-300');
selectedStyle = option.dataset.style;
});
});
voiceOptions.forEach(option => {
option.addEventListener('click', () => {
voiceOptions.forEach(opt => opt.classList.remove('selected'));
option.classList.add('selected');
selectedVoice = option.dataset.voice;
const gender = option.dataset.gender;
// Update voice preview
voiceName.textContent = option.querySelector('p.font-medium').textContent;
voiceDesc.textContent = option.querySelector('p.text-xs').textContent;
if (gender === 'female') {
voiceGenderIcon.className = 'fas fa-female text-pink-500';
voiceIcon.className = 'w-10 h-10 rounded-full bg-pink-100 flex items-center justify-center mr-3';
} else {
voiceGenderIcon.className = 'fas fa-male text-blue-500';
voiceIcon.className = 'w-10 h-10 rounded-full bg-blue-100 flex items-center justify-center mr-3';
}
voicePreviewContainer.classList.remove('hidden');
nextStep3.disabled = !speechText.value.trim();
});
});
speechText.addEventListener('input', () => {
const text = speechText.value.trim();
charCount.textContent = `${text.length} caractères`;
nextStep3.disabled = !text || !selectedVoice;
});
generateBtn.addEventListener('click', generateVideo);
downloadBtn.addEventListener('click', () => {
if (generatedVideo.src) {
const a = document.createElement('a');
a.href = generatedVideo.src;
a.download = `video-${Date.now()}.mp4`;
a.click();
}
});
textToSpeechPreview.addEventListener('click', previewTextToSpeech);
playVoicePreview.addEventListener('click', previewVoice);
// Functions
function handleFileSelect(e) {
const file = e.target.files[0];
if (file && file.type.match('image.*')) {
selectedImage = file;
const reader = new FileReader();
reader.onload = function(event) {
imagePreview.src = event.target.result;
imagePreviewContainer.classList.remove('hidden');
nextStep1.disabled = false;
};
reader.readAsDataURL(file);
}
}
function navigateToStep(step) {
// Hide all step contents
stepContents.forEach(content => content.classList.add('hidden'));
// Show current step content
document.getElementById(`step${step}`).classList.remove('hidden');
// Update step indicator
currentStep = step;
updateStepIndicator();
// Update summary if going to step 4
if (step === 4) {
updateSummary();
}
}
function updateStepIndicator() {
steps.forEach((step, index) => {
const number = step.querySelector('div');
const text = step.querySelector('p');
if (index + 1 < currentStep) {
// Completed step
number.className = 'w-10 h-10 mx-auto rounded-full bg-green-500 text-white flex items-center justify-center font-bold';
text.className = 'mt-2 text-sm font-medium text-green-600';
} else if (index + 1 === currentStep) {
// Current step
number.className = 'w-10 h-10 mx-auto rounded-full bg-indigo-600 text-white flex items-center justify-center font-bold';
text.className = 'mt-2 text-sm font-medium text-indigo-600';
} else {
// Future step
number.className = 'w-10 h-10 mx-auto rounded-full bg-gray-200 text-gray-600 flex items-center justify-center font-bold';
text.className = 'mt-2 text-sm font-medium text-gray-500';
}
});
}
function updateSummary() {
if (selectedImage) {
summaryImage.src = imagePreview.src;
summaryImageName.textContent = selectedImage.name;
}
summaryPrompt.textContent = document.getElementById('prompt').value;
summaryDuration.textContent = `${duration.value} secondes`;
// Get selected style text
let styleText = 'Réaliste';
styleOptions.forEach(option => {
if (option.classList.contains('bg-indigo-50')) {
styleText = option.textContent.trim();
}
});
summaryStyle.textContent = styleText;
// Get selected voice
voiceOptions.forEach(option => {
if (option.classList.contains('selected')) {
const gender = option.dataset.gender;
summaryVoice.textContent = option.querySelector('p.font-medium').textContent;
if (gender === 'female') {
summaryVoiceGenderIcon.className = 'fas fa-female text-pink-500 text-xs';
summaryVoiceIcon.className = 'w-8 h-8 rounded-full bg-pink-100 flex items-center justify-center mr-2';
} else {
summaryVoiceGenderIcon.className = 'fas fa-male text-blue-500 text-xs';
summaryVoiceIcon.className = 'w-8 h-8 rounded-full bg-blue-100 flex items-center justify-center mr-2';
}
}
});
summaryText.textContent = speechText.value;
}
function generateVideo() {
// Simulate generation process
generationStatus.innerHTML = `
<div class="animate-pulse flex flex-col items-center">
<i class="fas fa-cog fa-spin text-4xl text-indigo-500 mb-4"></i>
<h3 class="text-xl font-medium mb-2">Génération en cours</h3>
<p class="text-gray-600 mb-6">Cela peut prendre quelques minutes...</p>
</div>
`;
progressContainer.classList.remove('hidden');
progressText.classList.remove('hidden');
generatedVideo.classList.add('hidden');
downloadSection.classList.add('hidden');
// Simulate progress updates
let progress = 0;
const interval = setInterval(() => {
progress += Math.random() * 10;
if (progress > 100) progress = 100;
progressBar.style.width = `${progress}%`;
if (progress < 30) {
progressText.textContent = "Préparation des données...";
} else if (progress < 60) {
progressText.textContent = "Génération de l'animation faciale...";
} else if (progress < 90) {
progressText.textContent = "Synthèse vocale en cours...";
} else {
progressText.textContent = "Finalisation de la vidéo...";
}
if (progress === 100) {
clearInterval(interval);
setTimeout(() => {
showGeneratedVideo();
}, 1000);
}
}, 500);
}
function showGeneratedVideo() {
// In a real app, this would be the actual generated video URL
// For demo purposes, we'll use a placeholder
generatedVideo.src = "https://sample-videos.com/video123/mp4/720/big_buck_bunny_720p_1mb.mp4";
generatedVideo.classList.remove('hidden');
downloadSection.classList.remove('hidden');
generationStatus.innerHTML = `
<i class="fas fa-check-circle text-4xl text-green-500 mb-4"></i>
<h3 class="text-xl font-medium mb-2">Vidéo générée avec succès !</h3>
<p class="text-gray-600">Votre vidéo est prête à être téléchargée.</p>
`;
}
function previewTextToSpeech() {
if (!audioContext) {
audioContext = new (window.AudioContext || window.webkitAudioContext)();
}
// In a real app, this would call a TTS API
alert("Pré-écoute du texte avec la voix sélectionnée (simulation)");
}
function previewVoice() {
if (!audioContext) {
audioContext = new (window.AudioContext || window.webkitAudioContext)();
}
// In a real app, this would play a sample of the selected voice
alert("Pré-écoute de la voix sélectionnée (simulation)");
}
});
</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=AdamAI777/image-to-video" style="color: #fff;text-decoration: underline;" target="_blank" >🧬 Remix</a></p><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=deepnd/i2v" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>