hellotra / index.html
Dannylova31's picture
Add 3 files
8b9b8fe verified
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>NaweliMed Pro - Traducteur PDF Multilingue</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.11.338/pdf.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
.dropzone {
border: 2px dashed #3b82f6;
border-radius: 0.5rem;
transition: all 0.3s ease;
}
.dropzone.active {
border-color: #10b981;
background-color: #f0fdf4;
}
.progress-bar {
transition: width 0.3s ease;
}
#pdfViewer {
border: 1px solid #e5e7eb;
border-radius: 0.5rem;
overflow: hidden;
}
.language-flag {
width: 24px;
height: 16px;
display: inline-block;
margin-right: 8px;
background-size: cover;
border-radius: 2px;
}
.logo {
background: linear-gradient(135deg, #3b82f6 0%, #10b981 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
</style>
</head>
<body class="bg-gray-50 min-h-screen">
<div class="container mx-auto px-4 py-8">
<header class="text-center mb-8">
<div class="flex items-center justify-center mb-2">
<i class="fas fa-file-pdf text-4xl mr-3 logo"></i>
<h1 class="text-4xl font-bold logo">NaweliMed Pro</h1>
</div>
<p class="text-gray-600">Solution professionnelle de traduction de documents médicaux</p>
</header>
<div class="bg-white rounded-xl shadow-lg overflow-hidden mb-8">
<div class="p-6">
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<!-- PDF Upload Section -->
<div class="space-y-4">
<h2 class="text-xl font-semibold text-gray-800 flex items-center">
<i class="fas fa-file-upload mr-2 text-blue-500"></i> Importer un PDF
</h2>
<div id="dropzone" class="dropzone p-8 text-center cursor-pointer hover:bg-blue-50 transition-colors duration-200">
<div class="flex flex-col items-center justify-center space-y-2">
<svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 text-blue-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<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>
<p class="text-gray-600">Glissez-déposez votre fichier PDF ici ou cliquez pour sélectionner</p>
<p class="text-sm text-gray-500">Taille maximale: 10MB</p>
</div>
<input type="file" id="fileInput" class="hidden" accept=".pdf">
</div>
<div id="fileInfo" class="hidden bg-blue-50 p-3 rounded-lg border border-blue-100">
<div class="flex justify-between items-center">
<div>
<p class="font-medium text-blue-800 flex items-center">
<i class="fas fa-file-pdf mr-2"></i>
<span id="fileName"></span>
</p>
<p class="text-sm text-blue-600 ml-6" id="fileSize"></p>
</div>
<button id="removeFile" class="text-red-500 hover:text-red-700">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z" clip-rule="evenodd" />
</svg>
</button>
</div>
</div>
</div>
<!-- Language Selection Section -->
<div class="space-y-4">
<h2 class="text-xl font-semibold text-gray-800 flex items-center">
<i class="fas fa-language mr-2 text-blue-500"></i> Sélection des langues
</h2>
<div class="space-y-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1 flex items-center">
<i class="fas fa-arrow-down mr-2 text-gray-500"></i> Langue source
</label>
<select id="sourceLang" class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500">
<option value="fr">
<span class="language-flag" style="background-image: url('https://flagcdn.com/16x12/fr.png')"></span>
Français
</option>
<option value="en">
<span class="language-flag" style="background-image: url('https://flagcdn.com/16x12/gb.png')"></span>
Anglais
</option>
<option value="nl">
<span class="language-flag" style="background-image: url('https://flagcdn.com/16x12/nl.png')"></span>
Néerlandais
</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1 flex items-center">
<i class="fas fa-arrow-up mr-2 text-gray-500"></i> Langue cible
</label>
<select id="targetLang" class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500">
<option value="en">
<span class="language-flag" style="background-image: url('https://flagcdn.com/16x12/gb.png')"></span>
Anglais
</option>
<option value="fr">
<span class="language-flag" style="background-image: url('https://flagcdn.com/16x12/fr.png')"></span>
Français
</option>
<option value="nl">
<span class="language-flag" style="background-image: url('https://flagcdn.com/16x12/nl.png')"></span>
Néerlandais
</option>
</select>
</div>
<div class="flex items-center">
<input id="preserveFormatting" type="checkbox" class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded">
<label for="preserveFormatting" class="ml-2 block text-sm text-gray-700">
<i class="fas fa-text-height mr-1"></i> Conserver la mise en forme
</label>
</div>
</div>
</div>
</div>
<!-- PDF Preview Section -->
<div id="pdfPreviewSection" class="hidden mt-6">
<h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">
<i class="fas fa-eye mr-2 text-blue-500"></i> Aperçu du PDF
</h2>
<div id="pdfViewer" class="w-full h-64 bg-gray-100 flex items-center justify-center rounded-lg">
<p class="text-gray-500 flex flex-col items-center">
<i class="fas fa-file-pdf text-4xl mb-2 text-gray-400"></i>
Aperçu du PDF sera affiché ici
</p>
</div>
<div class="mt-2 flex justify-between items-center">
<div class="text-sm text-gray-500">
<i class="fas fa-file-alt mr-1"></i> Pages: <span id="pageCount">0</span>
</div>
<div class="flex space-x-2">
<button id="prevPage" class="px-3 py-1 bg-gray-200 rounded-md text-gray-700 hover:bg-gray-300 transition-colors disabled:opacity-50 flex items-center">
<i class="fas fa-chevron-left mr-1"></i> Précédent
</button>
<span class="px-3 py-1 text-gray-700 flex items-center">
<i class="fas fa-file mr-1"></i> Page <span id="currentPage">1</span>
</span>
<button id="nextPage" class="px-3 py-1 bg-gray-200 rounded-md text-gray-700 hover:bg-gray-300 transition-colors disabled:opacity-50 flex items-center">
Suivant <i class="fas fa-chevron-right ml-1"></i>
</button>
</div>
</div>
</div>
<!-- Action Buttons -->
<div class="mt-6 flex flex-col sm:flex-row justify-end space-y-2 sm:space-y-0 sm:space-x-3">
<button id="translateBtn" class="px-6 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed transition-colors flex items-center">
<i class="fas fa-language mr-2"></i> Traduire le document
</button>
<button id="exportBtn" class="px-6 py-2 bg-green-600 text-white rounded-md hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed transition-colors flex items-center">
<i class="fas fa-file-excel mr-2"></i> Exporter en Excel
</button>
</div>
</div>
<!-- Progress Bar -->
<div id="progressContainer" class="hidden bg-gray-100 border-t border-gray-200">
<div class="px-6 py-3">
<div class="flex justify-between mb-1">
<span class="text-sm font-medium text-blue-700 flex items-center">
<i class="fas fa-spinner fa-spin mr-2"></i> Progression
</span>
<span class="text-sm font-medium text-blue-700" id="progressPercent">0%</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2.5">
<div id="progressBar" class="progress-bar bg-blue-600 h-2.5 rounded-full" style="width: 0%"></div>
</div>
</div>
</div>
</div>
<!-- Translation Results -->
<div id="resultsSection" class="hidden bg-white rounded-xl shadow-lg overflow-hidden mt-8">
<div class="p-6">
<h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">
<i class="fas fa-list-check mr-2 text-blue-500"></i> Résultats de la traduction
</h2>
<div class="overflow-x-auto">
<table id="resultsTable" class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
<i class="fas fa-file-alt mr-1"></i> Page
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
<i class="fas fa-font mr-1"></i> Texte original
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
<i class="fas fa-exchange-alt mr-1"></i> Traduction
</th>
</tr>
</thead>
<tbody id="resultsBody" class="bg-white divide-y divide-gray-200">
<!-- Results will be inserted here -->
</tbody>
</table>
</div>
</div>
</div>
<!-- Footer -->
<footer class="mt-12 text-center text-gray-500 text-sm">
<p>© 2023 NaweliMed Pro - Solution professionnelle de traduction médicale</p>
<p class="mt-1">Développé avec <i class="fas fa-heart text-red-500"></i> pour les professionnels de santé</p>
</footer>
</div>
<script>
// Initialize PDF.js worker
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.11.338/pdf.worker.min.js';
// DOM Elements
const dropzone = document.getElementById('dropzone');
const fileInput = document.getElementById('fileInput');
const fileInfo = document.getElementById('fileInfo');
const fileName = document.getElementById('fileName');
const fileSize = document.getElementById('fileSize');
const removeFile = document.getElementById('removeFile');
const translateBtn = document.getElementById('translateBtn');
const exportBtn = document.getElementById('exportBtn');
const pdfPreviewSection = document.getElementById('pdfPreviewSection');
const pdfViewer = document.getElementById('pdfViewer');
const pageCount = document.getElementById('pageCount');
const currentPage = document.getElementById('currentPage');
const prevPage = document.getElementById('prevPage');
const nextPage = document.getElementById('nextPage');
const progressContainer = document.getElementById('progressContainer');
const progressBar = document.getElementById('progressBar');
const progressPercent = document.getElementById('progressPercent');
const resultsSection = document.getElementById('resultsSection');
const resultsBody = document.getElementById('resultsBody');
const sourceLang = document.getElementById('sourceLang');
const targetLang = document.getElementById('targetLang');
// State variables
let pdfDoc = null;
let currentPageNum = 1;
let pdfTextContent = [];
let translatedContent = [];
let isTranslating = false;
// Event Listeners
dropzone.addEventListener('click', () => fileInput.click());
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;
handleFileUpload(e.dataTransfer.files[0]);
}
});
fileInput.addEventListener('change', () => {
if (fileInput.files.length) {
handleFileUpload(fileInput.files[0]);
}
});
removeFile.addEventListener('click', resetFileInput);
prevPage.addEventListener('click', () => {
if (currentPageNum > 1) {
currentPageNum--;
renderPage();
}
});
nextPage.addEventListener('click', () => {
if (currentPageNum < pdfDoc.numPages) {
currentPageNum++;
renderPage();
}
});
translateBtn.addEventListener('click', translateDocument);
exportBtn.addEventListener('click', exportToExcel);
// Functions
function handleFileUpload(file) {
if (file.type !== 'application/pdf') {
alert('Veuillez sélectionner un fichier PDF valide.');
return;
}
if (file.size > 10 * 1024 * 1024) {
alert('Le fichier est trop volumineux. Taille maximale: 10MB');
return;
}
// Display file info
fileName.textContent = file.name;
fileSize.textContent = `${(file.size / 1024 / 1024).toFixed(2)} MB`;
fileInfo.classList.remove('hidden');
// Enable translate button
translateBtn.disabled = false;
// Load PDF for preview
const fileReader = new FileReader();
fileReader.onload = function() {
const typedArray = new Uint8Array(this.result);
loadPdf(typedArray);
};
fileReader.readAsArrayBuffer(file);
}
function loadPdf(data) {
pdfjsLib.getDocument(data).promise.then(function(pdf) {
pdfDoc = pdf;
pageCount.textContent = pdf.numPages;
currentPageNum = 1;
renderPage();
pdfPreviewSection.classList.remove('hidden');
// Disable prev button initially
prevPage.disabled = true;
nextPage.disabled = pdf.numPages <= 1;
}).catch(function(error) {
console.error('Error loading PDF:', error);
alert('Erreur lors du chargement du PDF. Veuillez réessayer.');
});
}
function renderPage() {
pdfDoc.getPage(currentPageNum).then(function(page) {
const viewport = page.getViewport({ scale: 1.0 });
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
// Clear previous content
pdfViewer.innerHTML = '';
pdfViewer.appendChild(canvas);
// Render PDF page
page.render({
canvasContext: context,
viewport: viewport
});
// Update page controls
currentPage.textContent = currentPageNum;
prevPage.disabled = currentPageNum <= 1;
nextPage.disabled = currentPageNum >= pdfDoc.numPages;
// Extract text content
page.getTextContent().then(function(textContent) {
const textItems = textContent.items.map(item => item.str).join(' ');
if (!pdfTextContent[currentPageNum - 1]) {
pdfTextContent[currentPageNum - 1] = textItems;
}
});
});
}
function resetFileInput() {
fileInput.value = '';
fileInfo.classList.add('hidden');
pdfPreviewSection.classList.add('hidden');
resultsSection.classList.add('hidden');
translateBtn.disabled = true;
exportBtn.disabled = true;
pdfDoc = null;
pdfTextContent = [];
translatedContent = [];
}
function translateDocument() {
if (isTranslating) return;
const source = sourceLang.value;
const target = targetLang.value;
if (source === target) {
alert('Les langues source et cible doivent être différentes.');
return;
}
isTranslating = true;
translateBtn.disabled = true;
progressContainer.classList.remove('hidden');
progressBar.style.width = '0%';
progressPercent.textContent = '0%';
// Simulate translation progress (in a real app, this would be API calls)
let progress = 0;
translatedContent = [];
const totalPages = pdfDoc.numPages;
const progressInterval = setInterval(() => {
progress += Math.random() * 10;
if (progress >= 100) {
progress = 100;
clearInterval(progressInterval);
// Simulate translation results
for (let i = 0; i < pdfTextContent.length; i++) {
const originalText = pdfTextContent[i] || `Contenu de la page ${i + 1}`;
let translatedText = '';
// Simple mock translation based on language pairs
if (source === 'fr' && target === 'en') {
translatedText = `[English translation of: ${originalText.substring(0, 30)}...]`;
} else if (source === 'fr' && target === 'nl') {
translatedText = `[Dutch translation of: ${originalText.substring(0, 30)}...]`;
} else if (source === 'en' && target === 'fr') {
translatedText = `[Traduction française de: ${originalText.substring(0, 30)}...]`;
} else if (source === 'en' && target === 'nl') {
translatedText = `[Nederlandse vertaling van: ${originalText.substring(0, 30)}...]`;
} else if (source === 'nl' && target === 'fr') {
translatedText = `[Traduction française de: ${originalText.substring(0, 30)}...]`;
} else if (source === 'nl' && target === 'en') {
translatedText = `[English translation of: ${originalText.substring(0, 30)}...]`;
}
translatedContent.push({
page: i + 1,
original: originalText,
translation: translatedText
});
}
displayResults();
isTranslating = false;
exportBtn.disabled = false;
}
progressBar.style.width = `${progress}%`;
progressPercent.textContent = `${Math.round(progress)}%`;
}, 300);
}
function displayResults() {
resultsBody.innerHTML = '';
translatedContent.forEach(item => {
const row = document.createElement('tr');
const pageCell = document.createElement('td');
pageCell.className = 'px-6 py-4 whitespace-nowrap text-sm text-gray-500';
pageCell.textContent = item.page;
const originalCell = document.createElement('td');
originalCell.className = 'px-6 py-4 text-sm text-gray-900';
originalCell.textContent = item.original.length > 100
? item.original.substring(0, 100) + '...'
: item.original;
const translationCell = document.createElement('td');
translationCell.className = 'px-6 py-4 text-sm text-gray-900';
translationCell.textContent = item.translation.length > 100
? item.translation.substring(0, 100) + '...'
: item.translation;
row.appendChild(pageCell);
row.appendChild(originalCell);
row.appendChild(translationCell);
resultsBody.appendChild(row);
});
resultsSection.classList.remove('hidden');
}
function exportToExcel() {
if (translatedContent.length === 0) {
alert('Aucune donnée à exporter. Veuillez d\'abord traduire le document.');
return;
}
// Prepare worksheet
const wsData = [
['Page', 'Texte original', 'Traduction'],
...translatedContent.map(item => [item.page, item.original, item.translation])
];
const ws = XLSX.utils.aoa_to_sheet(wsData);
// Create workbook
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, 'Traduction');
// Generate file name
const fileName = `NaweliMed_Pro_traduction_${sourceLang.value}_to_${targetLang.value}_${new Date().toISOString().slice(0, 10)}.xlsx`;
// Export
XLSX.writeFile(wb, fileName);
}
</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=Dannylova31/hellotra" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>