Spaces:
Sleeping
Sleeping
<html lang="fr"> | |
<!-- [Head section reste identique jusqu'aux styles] --> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Mariam Espagnol - Analyse de Documents</title> | |
<script src="https://cdn.tailwindcss.com"></script> | |
<script src="https://unpkg.com/[email protected]/marked.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/prismjs/1.24.1/prism.min.js"></script> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prismjs/1.24.1/themes/prism.min.css"> | |
<style> | |
@import url('https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;700&family=Poppins:wght@300;400;500;600&display=swap'); | |
.fade-in { | |
animation: fadeIn 0.5s ease-in; | |
} | |
.slide-up { | |
animation: slideUp 0.5s ease-out; | |
} | |
@keyframes fadeIn { | |
from { opacity: 0; } | |
to { opacity: 1; } | |
} | |
@keyframes slideUp { | |
from { transform: translateY(20px); opacity: 0; } | |
to { transform: translateY(0); opacity: 1; } | |
} | |
.gradient-text { | |
background: linear-gradient(45deg, #FF6B6B, #4ECDC4); | |
-webkit-background-clip: text; | |
background-clip: text; | |
color: transparent; | |
} | |
.upload-zone { | |
background: linear-gradient(145deg, #ffffff, #f3f4f6); | |
box-shadow: 20px 20px 60px #d1d1d1, | |
-20px -20px 60px #ffffff; | |
} | |
.upload-zone:hover { | |
transform: scale(1.01); | |
transition: all 0.3s ease; | |
} | |
.waves { | |
position: absolute; | |
bottom: 0; | |
left: 0; | |
width: 100%; | |
overflow: hidden; | |
line-height: 0; | |
transform: rotate(180deg); | |
} | |
.waves svg { | |
position: relative; | |
display: block; | |
width: calc(100% + 1.3px); | |
height: 150px; | |
} | |
.prose { | |
max-width: none; | |
color: #374151; | |
} | |
.prose h1, .prose h2, .prose h3 { | |
color: #1F2937; | |
font-family: 'Playfair Display', serif; | |
margin-top: 2em; | |
margin-bottom: 1em; | |
} | |
.prose p { | |
margin-bottom: 1.5em; | |
line-height: 1.8; | |
} | |
/* [Styles précédents restent identiques] */ | |
.button-submit { | |
background: linear-gradient(45deg, #4F46E5, #818CF8); | |
transition: all 0.3s ease; | |
} | |
.button-submit:hover { | |
transform: translateY(-2px); | |
box-shadow: 0 10px 20px rgba(79, 70, 229, 0.2); | |
} | |
.option-card { | |
transition: all 0.3s ease; | |
} | |
.option-card:hover { | |
transform: translateY(-5px); | |
} | |
.file-input { | |
display: none; | |
} | |
</style> | |
</head> | |
<body class="bg-gradient-to-br from-gray-50 to-gray-100 min-h-screen relative"> | |
<!-- [Waves section reste identique] --> | |
<div class="waves"> | |
<svg data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 120" preserveAspectRatio="none"> | |
<path d="M321.39,56.44c58-10.79,114.16-30.13,172-41.86,82.39-16.72,168.19-17.73,250.45-.39C823.78,31,906.67,72,985.66,92.83c70.05,18.48,146.53,26.09,214.34,3V0H0V27.35A600.21,600.21,0,0,0,321.39,56.44Z" class="fill-indigo-50"></path> | |
</svg> | |
</div> | |
<div class="max-w-6xl mx-auto px-4 py-12 relative z-10"> | |
<!-- Header --> | |
<header class="text-center mb-16 fade-in"> | |
<h1 class="text-5xl md:text-6xl font-bold mb-4 font-['Playfair_Display'] gradient-text"> | |
Mariam Espagnol | |
</h1> | |
<p class="text-xl text-gray-600 font-light max-w-2xl mx-auto"> | |
Analysez vos documents en espagnol avec une traduction française précise et élégante | |
</p> | |
</header> | |
<!-- Main Content --> | |
<div class="bg-white rounded-2xl shadow-xl p-6 md:p-8 mb-8 slide-up"> | |
<!-- Document Type Selection --> | |
<div class="mb-8 grid md:grid-cols-2 gap-6"> | |
<div class="option-card p-6 rounded-xl border-2 border-gray-200 hover:border-indigo-500 cursor-pointer transition-all" | |
onclick="selectDocType('iconographic')"> | |
<input type="radio" name="docType" value="iconographic" class="sr-only" checked> | |
<div class="flex items-center mb-4"> | |
<svg class="w-8 h-8 text-indigo-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"/> | |
</svg> | |
<h3 class="ml-3 text-lg font-semibold">Document Iconographique</h3> | |
</div> | |
<p class="text-gray-600 text-sm">Images, photos, illustrations, publicités, etc.</p> | |
</div> | |
<div class="option-card p-6 rounded-xl border-2 border-gray-200 hover:border-indigo-500 cursor-pointer transition-all" | |
onclick="selectDocType('textual')"> | |
<input type="radio" name="docType" value="textual" class="sr-only"> | |
<div class="flex items-center mb-4"> | |
<svg class="w-8 h-8 text-indigo-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/> | |
</svg> | |
<h3 class="ml-3 text-lg font-semibold">Document Textuel</h3> | |
</div> | |
<p class="text-gray-600 text-sm">Textes, articles, documents écrits, etc.</p> | |
</div> | |
</div> | |
<!-- File Selection --> | |
<div class="mb-8"> | |
<button onclick="openFileSelection()" class="w-full py-4 px-6 rounded-xl bg-indigo-50 hover:bg-indigo-100 transition-colors flex items-center justify-center gap-3"> | |
<svg class="w-6 h-6 text-indigo-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12"/> | |
</svg> | |
<span class="text-indigo-700 font-medium">Sélectionner depuis la galerie</span> | |
</button> | |
<input type="file" id="file-upload" class="file-input" accept="image/*,text/*" | |
capture="environment" multiple> | |
</div> | |
<!-- Upload Zone --> | |
<div class="upload-zone border-2 border-dashed border-gray-300 rounded-2xl p-8 text-center cursor-pointer transition-all duration-300 relative overflow-hidden"> | |
<div class="space-y-4"> | |
<div class="w-20 h-20 mx-auto rounded-full bg-indigo-50 flex items-center justify-center"> | |
<svg class="w-10 h-10 text-indigo-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"/> | |
</svg> | |
</div> | |
<div class="text-sm text-gray-600"> | |
<p>Déposez votre fichier ici</p> | |
<p class="text-xs text-gray-500 mt-2">ou</p> | |
<p class="text-indigo-600 font-medium mt-2">Cliquez pour sélectionner</p> | |
</div> | |
</div> | |
</div> | |
<!-- Preview --> | |
<div id="preview" class="mt-12 hidden slide-up"> | |
<h3 class="text-xl font-medium text-gray-900 mb-6">Aperçu du document</h3> | |
<div class="preview-container border rounded-xl p-6 bg-gray-50"> | |
<img id="image-preview" class="max-w-full h-auto hidden rounded-lg shadow-lg" alt="Aperçu"> | |
<pre id="text-preview" class="text-sm text-gray-700 whitespace-pre-wrap hidden bg-white p-4 rounded-lg shadow-inner"></pre> | |
</div> | |
</div> | |
<!-- Submit Button --> | |
<div class="mt-8"> | |
<button id="submit-button" | |
class="button-submit w-full py-4 px-8 rounded-xl text-white font-medium text-lg disabled:opacity-50 disabled:cursor-not-allowed hidden" | |
onclick="submitAnalysis()"> | |
Analyser le document | |
</button> | |
</div> | |
<!-- Analysis Results --> | |
<div id="results" class="mt-12 hidden slide-up"> | |
<h3 class="text-xl font-medium text-gray-900 mb-6">Analyse détaillée</h3> | |
<div class="bg-white rounded-xl p-6 shadow-inner"> | |
<div id="analysis-content" class="prose prose-indigo"></div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Loading Spinner --> | |
<div id="loading" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden backdrop-blur-sm z-50"> | |
<div class="bg-white p-8 rounded-2xl shadow-2xl"> | |
<div class="animate-spin rounded-full h-16 w-16 border-t-4 border-b-4 border-indigo-500 mx-auto"></div> | |
<p class="text-gray-700 mt-4">Analyse en cours...</p> | |
</div> | |
</div> | |
<script> | |
let selectedFile = null; | |
function selectDocType(type) { | |
document.querySelectorAll('.option-card').forEach(card => { | |
card.classList.remove('border-indigo-500'); | |
card.classList.add('border-gray-200'); | |
}); | |
const selectedCard = document.querySelector(`[onclick="selectDocType('${type}')"]`); | |
selectedCard.classList.remove('border-gray-200'); | |
selectedCard.classList.add('border-indigo-500'); | |
const radio = selectedCard.querySelector('input[type="radio"]'); | |
radio.checked = true; | |
} | |
function openFileSelection() { | |
document.getElementById('file-upload').click(); | |
} | |
function handleFile(file) { | |
selectedFile = file; | |
const submitButton = document.getElementById('submit-button'); | |
submitButton.classList.remove('hidden'); | |
// Preview logic | |
const preview = document.getElementById('preview'); | |
const imagePreview = document.getElementById('image-preview'); | |
const textPreview = document.getElementById('text-preview'); | |
preview.classList.remove('hidden'); | |
preview.classList.add('fade-in'); | |
const docType = document.querySelector('input[name="docType"]:checked').value; | |
if (docType === 'iconographic' && file.type.startsWith('image/')) { | |
imagePreview.classList.remove('hidden'); | |
textPreview.classList.add('hidden'); | |
const reader = new FileReader(); | |
reader.onload = (e) => { | |
imagePreview.src = e.target.result; | |
imagePreview.classList.add('fade-in'); | |
}; | |
reader.readAsDataURL(file); | |
} else { | |
imagePreview.classList.add('hidden'); | |
textPreview.classList.remove('hidden'); | |
const reader = new FileReader(); | |
reader.onload = (e) => { | |
textPreview.textContent = e.target.result; | |
textPreview.classList.add('fade-in'); | |
}; | |
reader.readAsText(file); | |
} | |
} | |
function submitAnalysis() { | |
if (!selectedFile) return; | |
const formData = new FormData(); | |
formData.append('file', selectedFile); | |
formData.append('docType', document.querySelector('input[name="docType"]:checked').value); | |
const loading = document.getElementById('loading'); | |
const results = document.getElementById('results'); | |
const analysisContent = document.getElementById('analysis-content'); | |
loading.classList.remove('hidden'); | |
loading.classList.add('fade-in'); | |
fetch('/upload', { | |
method: 'POST', | |
body: formData | |
}) | |
.then(response => response.json()) | |
.then(data => { | |
loading.classList.add('hidden'); | |
results.classList.remove('hidden'); | |
results.classList.add('slide-up'); | |
analysisContent.innerHTML = marked.parse(data.analysis); | |
Prism.highlightAll(); | |
}) | |
.catch(error => { | |
loading.classList.add('hidden'); | |
alert('Une erreur est survenue lors de l\'analyse. Veuillez réessayer.'); | |
console.error('Error:', error); | |
}); | |
} | |
// Event Listeners | |
document.addEventListener('DOMContentLoaded', function() { | |
const uploadZone = document.querySelector('.upload-zone'); | |
const fileInput = document.getElementById('file-upload'); | |
uploadZone.addEventListener('click', () => fileInput.click()); | |
uploadZone.addEventListener('dragover', (e) => { | |
e.preventDefault(); | |
uploadZone.classList.add('border-indigo-500', 'bg-indigo-50'); | |
}); | |
uploadZone.addEventListener('dragleave', () => { | |
uploadZone.classList.remove('border-indigo-500', 'bg-indigo-50'); | |
}); | |
uploadZone.addEventListener('drop', (e) => { | |
e.preventDefault(); | |
uploadZone.classList.remove('border-indigo-500', 'bg-indigo-50'); | |
const files = e.dataTransfer.files; | |
if (files.length) handleFile(files[0]); | |
}); | |
fileInput.addEventListener('change', (e) => { | |
if (e.target.files.length) handleFile(e.target.files[0]); | |
}); | |
}); | |
</script> | |
</body> | |
</html> |