// JavaScript principal pour l'application FaceSwap Magic // DOM Elements const originalUpload = document.getElementById('original-upload'); const targetUpload = document.getElementById('target-upload'); const originalPreview = document.getElementById('original-preview'); const targetPreview = document.getElementById('target-preview'); const originalImage = document.getElementById('original-image'); const targetImage = document.getElementById('target-image'); const generateBtn = document.getElementById('generate-btn'); const resultSection = document.getElementById('result-section'); const resultImage = document.getElementById('result-image'); const displayOriginal = document.getElementById('display-original'); const downloadBtn = document.getElementById('download-btn'); const shareBtn = document.getElementById('share-btn'); const tryAgainBtn = document.getElementById('try-again-btn'); // Sample results for demo purposes (using placeholder API) const sampleResults = [ 'http://static.photos/people/640x360/201', 'http://static.photos/people/640x360/202', 'http://static.photos/people/640x360/203', 'http://static.photos/people/640x360/204', 'http://static.photos/people/640x360/205' ]; // State Management let currentState = { originalImage: null, targetImage: null, generatedResult: null, isProcessing: false }; // Initialize Application document.addEventListener('DOMContentLoaded', function() { console.log('FaceSwap Magic initialisé !'); // Set up event listeners setupEventListeners(); // Check for saved state in localStorage loadSavedState(); // Initialize tooltips initializeTooltips(); // Add animation to hero section animateHeroSection(); }); // Set up all event listeners function setupEventListeners() { // File upload handlers originalUpload.addEventListener('change', (e) => handleFileUpload(e, 'original')); targetUpload.addEventListener('change', (e) => handleFileUpload(e, 'target')); // Generate button click generateBtn.addEventListener('click', generateFaceSwap); // Result buttons downloadBtn.addEventListener('click', downloadResult); shareBtn.addEventListener('click', shareResult); tryAgainBtn.addEventListener('click', resetApplication); // Drag and drop functionality setupDragAndDrop(); // Range slider updates setupRangeSliders(); } // Handle file upload function handleFileUpload(event, type) { const file = event.target.files[0]; if (!file) return; if (!file.type.match('image.*')) { showToast('Veuillez télécharger un fichier image', 'error'); return; } if (file.size > 10 * 1024 * 1024) { // 10MB limit showToast('La taille du fichier doit être inférieure à 10Mo', 'error'); return; } const reader = new FileReader(); reader.onload = function(e) { const imageUrl = e.target.result; if (type === 'original') { currentState.originalImage = imageUrl; originalImage.src = imageUrl; originalPreview.classList.remove('hidden'); displayOriginal.src = imageUrl; } else { currentState.targetImage = imageUrl; targetImage.src = imageUrl; targetPreview.classList.remove('hidden'); } // Enable generate button if both images are uploaded if (currentState.originalImage && currentState.targetImage) { generateBtn.disabled = false; generateBtn.classList.remove('opacity-50', 'cursor-not-allowed'); } showToast(`${type === 'original' ? 'Originale' : 'Cible'} image téléchargée avec succès !`, 'success'); // Save to localStorage saveState(); }; reader.readAsDataURL(file); } // Setup drag and drop functionality function setupDragAndDrop() { const uploadAreas = document.querySelectorAll('.border-dashed'); uploadAreas.forEach(area => { area.addEventListener('dragover', (e) => { e.preventDefault(); area.classList.add('border-primary', 'bg-primary/5'); }); area.addEventListener('dragleave', () => { area.classList.remove('border-primary', 'bg-primary/5'); }); area.addEventListener('drop', (e) => { e.preventDefault(); area.classList.remove('border-primary', 'bg-primary/5'); const file = e.dataTransfer.files[0]; if (file && file.type.match('image.*')) { // Simulate file input change const isOriginal = area.closest('.space-y-6').querySelector('h3').textContent.includes('Original'); const input = isOriginal ? originalUpload : targetUpload; // Create a new FileList (simulated) const dataTransfer = new DataTransfer(); dataTransfer.items.add(file); input.files = dataTransfer.files; // Trigger change event input.dispatchEvent(new Event('change')); } }); }); } // Setup range sliders function setupRangeSliders() { const sliders = document.querySelectorAll('input[type="range"]'); sliders.forEach(slider => { slider.addEventListener('input', function() { const value = this.value; const label = this.previousElementSibling; // Update label with percentage if (label && label.classList.contains('text-gray-700')) { const labelText = label.textContent.split(':')[0]; label.textContent = `${labelText}: ${value}%`; } }); }); } // Generate face swap (simulated) function generateFaceSwap() { if (!currentState.originalImage || !currentState.targetImage) { showToast('Veuillez télécharger les deux images d\'abord !', 'error'); return; } // Show loading state currentState.isProcessing = true; generateBtn.disabled = true; generateBtn.innerHTML = `
Traitement en cours... `; // Simulate API call delay setTimeout(() => { // Get random sample result for demo const randomIndex = Math.floor(Math.random() * sampleResults.length); currentState.generatedResult = sampleResults[randomIndex]; resultImage.src = currentState.generatedResult; // Show result section resultSection.classList.remove('hidden'); resultSection.scrollIntoView({ behavior: 'smooth' }); // Reset button generateBtn.disabled = false; generateBtn.innerHTML = ` Générer l'Échange `; feather.replace(); currentState.isProcessing = false; showToast('Échange de visage généré avec succès !', 'success'); // Save state saveState(); }, 3000); } // Download result function downloadResult() { if (!currentState.generatedResult) { showToast('Aucun résultat à télécharger !', 'error'); return; } // In a real app, this would download the actual generated image // For demo, we'll create a download link const link = document.createElement('a'); link.href = currentState.generatedResult; link.download = `faceswap-${Date.now()}.jpg`; document.body.appendChild(link); link.click(); document.body.removeChild(link); showToast('Téléchargement démarré !', 'success'); } // Share result function shareResult() { if (!currentState.generatedResult) { showToast('Aucun résultat à partager !', 'error'); return; } if (navigator.share) { navigator.share({ title: 'My AI FaceSwap Creation', text: 'Check out this awesome face swap I made with FaceSwap Magic!', url: window.location.href }) .then(() => showToast('Partagé avec succès !', 'success')) .catch(() => showToast('Partage annulé', 'info')); } else { // Fallback: copy to clipboard navigator.clipboard.writeText(window.location.href) .then(() => showToast('Lien copié dans le presse-papier !', 'success')) .catch(() => showToast('Échec de la copie du lien', 'error')); } } // Reset application function resetApplication() { // Reset file inputs originalUpload.value = ''; targetUpload.value = ''; // Hide previews originalPreview.classList.add('hidden'); targetPreview.classList.add('hidden'); resultSection.classList.add('hidden'); // Reset images originalImage.src = ''; targetImage.src = ''; resultImage.src = ''; // Reset state currentState = { originalImage: null, targetImage: null, generatedResult: null, isProcessing: false }; // Reset range sliders document.querySelectorAll('input[type="range"]').forEach(slider => { slider.value = slider.id.includes('alignment') ? 50 : slider.id.includes('skin') ? 75 : 60; slider.dispatchEvent(new Event('input')); }); // Scroll to upload section document.getElementById('upload-section').scrollIntoView({ behavior: 'smooth' }); showToast('Prêt pour un nouvel échange de visage !', 'info'); // Clear localStorage localStorage.removeItem('faceswapState'); } // Show toast notification function showToast(message, type = 'info') { // Remove existing toasts document.querySelectorAll('.toast').forEach(toast => toast.remove()); // Create toast element const toast = document.createElement('div'); toast.className = 'toast'; // Set icon based on type let icon = 'info'; let bgColor = 'bg-blue-100'; let borderColor = 'border-blue-500'; if (type === 'success') { icon = 'check-circle'; bgColor = 'bg-green-100'; borderColor = 'border-green-500'; } else if (type === 'error') { icon = 'alert-circle'; bgColor = 'bg-red-100'; borderColor = 'border-red-500'; } else if (type === 'warning') { icon = 'alert-triangle'; bgColor = 'bg-yellow-100'; borderColor = 'border-yellow-500'; } toast.innerHTML = `