| <!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 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> |
|
|
| |
| <div class="bg-white rounded-xl shadow-lg overflow-hidden"> |
| |
| <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> |
|
|
| |
| <div class="p-8"> |
| |
| <div id="step1" class="step-content"> |
| <div class="grid md:grid-cols-2 gap-8"> |
| |
| <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> |
|
|
| |
| <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> |
|
|
| |
| <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"> |
| |
| <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> |
| |
| |
| <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> |
|
|
| |
| <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"> |
| |
| <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"> |
| |
| <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> |
| |
| |
| <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> |
| |
| |
| <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> |
| |
| |
| <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> |
|
|
| |
| <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"> |
| |
| <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> |
| |
| |
| <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> |
| |
| |
| <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> |
| |
| |
| <video id="generatedVideo" controls class="w-full rounded-lg hidden"></video> |
| |
| |
| <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() { |
| |
| 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'); |
| |
| |
| 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'); |
| |
| |
| let currentStep = 1; |
| let selectedImage = null; |
| let selectedStyle = 'realistic'; |
| let selectedVoice = null; |
| let audioContext = null; |
| |
| |
| updateStepIndicator(); |
| |
| |
| 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; |
| |
| |
| 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); |
| |
| |
| 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) { |
| |
| stepContents.forEach(content => content.classList.add('hidden')); |
| |
| |
| document.getElementById(`step${step}`).classList.remove('hidden'); |
| |
| |
| currentStep = step; |
| updateStepIndicator(); |
| |
| |
| if (step === 4) { |
| updateSummary(); |
| } |
| } |
| |
| function updateStepIndicator() { |
| steps.forEach((step, index) => { |
| const number = step.querySelector('div'); |
| const text = step.querySelector('p'); |
| |
| if (index + 1 < currentStep) { |
| |
| 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) { |
| |
| 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 { |
| |
| 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`; |
| |
| |
| let styleText = 'Réaliste'; |
| styleOptions.forEach(option => { |
| if (option.classList.contains('bg-indigo-50')) { |
| styleText = option.textContent.trim(); |
| } |
| }); |
| summaryStyle.textContent = styleText; |
| |
| |
| 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() { |
| |
| 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'); |
| |
| |
| 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() { |
| |
| |
| 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)(); |
| } |
| |
| |
| alert("Pré-écoute du texte avec la voix sélectionnée (simulation)"); |
| } |
| |
| function previewVoice() { |
| if (!audioContext) { |
| audioContext = new (window.AudioContext || window.webkitAudioContext)(); |
| } |
| |
| |
| 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> |