|
|
<!DOCTYPE html> |
|
|
<html lang="fr"> |
|
|
<head> |
|
|
<meta charset="UTF-8"> |
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
|
<title>Convertisseur et Générateur de Rapport</title> |
|
|
<style> |
|
|
body { font-family: sans-serif; margin: 20px; background-color: #f0f0f0; } |
|
|
.container { background-color: #fff; padding: 20px; border-radius: 8px; box-shadow: 0 0 10px rgba(0,0,0,0.1); max-width: 800px; margin: auto; } |
|
|
#htmlOutputContainer { border: 1px solid #ccc; margin-top: 20px; padding: 10px; min-height: 300px; background-color: #f9f9f9; overflow: auto; white-space: pre-wrap; font-family: monospace; } |
|
|
#loading { display: none; text-align: center; padding: 20px; font-style: italic; } |
|
|
button:disabled { background-color: #ccc; cursor: not-allowed; } |
|
|
.input-group { margin-bottom: 15px; } |
|
|
.input-group label { margin-right: 10px; font-weight: bold; } |
|
|
</style> |
|
|
|
|
|
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/mammoth/1.6.0/mammoth.browser.min.js"></script> |
|
|
|
|
|
|
|
|
<script type="module"> |
|
|
|
|
|
|
|
|
import { GoogleGenerativeAI, HarmCategory, HarmBlockThreshold } from "https://esm.run/@google/generative-ai"; |
|
|
|
|
|
const fileInput = document.getElementById('fileInput'); |
|
|
const languageSelect = document.getElementById('languageSelect'); |
|
|
const convertToHtmlButton = document.getElementById('convertToHtmlButton'); |
|
|
const htmlOutputContainer = document.getElementById('htmlOutputContainer'); |
|
|
const downloadButton = document.getElementById('downloadButton'); |
|
|
const generateReportButton = document.getElementById('generateReportButton'); |
|
|
const loadingDiv = document.getElementById('loading'); |
|
|
const previewHeader = document.getElementById('previewHeader'); |
|
|
const backToHtmlButton = document.getElementById('backToHtmlButton'); |
|
|
const applySuggestionsButton = document.getElementById('applySuggestionsButton'); |
|
|
|
|
|
let generatedWordHtml = ''; |
|
|
let reportText = ''; |
|
|
let correctedHtml = ''; |
|
|
|
|
|
|
|
|
const API_KEY = "AIzaSyAWwAhioiuTMAIHTyj9J3jpyVFmQ3OCoM0"; |
|
|
|
|
|
function cleanApiResponse(rawResponse) { |
|
|
const markdownMatch = rawResponse.match(/```html\s*([\s\S]*?)\s*```/); |
|
|
if (markdownMatch && markdownMatch[1]) { |
|
|
return markdownMatch[1].trim(); |
|
|
} |
|
|
const htmlMatch = rawResponse.match(/<!DOCTYPE html>[\s\S]*?<\/html>/i); |
|
|
if (htmlMatch && htmlMatch[0]) { |
|
|
|
|
|
const bodyMatch = htmlMatch[0].match(/<body[^>]*>([\s\S]*)<\/body>/i); |
|
|
return bodyMatch ? bodyMatch[1].trim() : htmlMatch[0]; |
|
|
} |
|
|
return rawResponse; |
|
|
} |
|
|
|
|
|
convertToHtmlButton.addEventListener('click', async () => { |
|
|
const file = fileInput.files[0]; |
|
|
if (!file) { |
|
|
alert("Veuillez sélectionner un fichier Word (.docx)."); |
|
|
return; |
|
|
} |
|
|
if (API_KEY.startsWith("AIzaSy") && API_KEY.length < 30) { |
|
|
alert("Veuillez remplacer la clé API de démonstration par votre véritable clé API Gemini."); |
|
|
return; |
|
|
} |
|
|
|
|
|
loadingDiv.style.display = 'block'; |
|
|
htmlOutputContainer.innerHTML = '<p>Étape 1/2 : Conversion du document en HTML...</p>'; |
|
|
downloadButton.style.display = 'none'; |
|
|
generateReportButton.style.display = 'none'; |
|
|
backToHtmlButton.style.display = 'none'; |
|
|
applySuggestionsButton.style.display = 'none'; |
|
|
previewHeader.textContent = 'Aperçu HTML:'; |
|
|
convertToHtmlButton.disabled = true; |
|
|
|
|
|
generatedWordHtml = ''; |
|
|
reportText = ''; |
|
|
correctedHtml = ''; |
|
|
|
|
|
try { |
|
|
const arrayBuffer = await file.arrayBuffer(); |
|
|
const mammothResult = await mammoth.convertToHtml({ arrayBuffer: arrayBuffer }); |
|
|
const initialHtml = mammothResult.value; |
|
|
|
|
|
htmlOutputContainer.innerHTML = '<p>Étape 2/2 : Traduction du contenu via l\'API...</p>'; |
|
|
|
|
|
const genAI = new GoogleGenerativeAI(API_KEY); |
|
|
const model = genAI.getGenerativeModel({ model: "gemini-2.5-pro-preview-06-05" }); |
|
|
const selectedLanguage = languageSelect.value; |
|
|
|
|
|
|
|
|
const prompt = ` |
|
|
Traduisez le contenu textuel de ce code HTML en ${selectedLanguage}. |
|
|
|
|
|
RÈGLE FONDAMENTALE : Vous devez préserver **ABSOLUMENT TOUTES** les balises HTML de l'original, y compris les balises de mise en forme de texte comme <em>, <i>, <strong>, et <b>. Ne traduisez que le texte qui se trouve entre les balises. |
|
|
|
|
|
Exemple de comportement attendu : |
|
|
- HTML D'ENTRÉE : <p>Ce texte est <em>vraiment</em> important.</p> |
|
|
- HTML DE SORTIE ATTENDU (pour l'anglais) : <p>This text is <em>really</em> important.</p> |
|
|
|
|
|
Ne modifiez, ne supprimez et n'ajoutez aucune balise HTML. Retournez UNIQUEMENT le code HTML complet et traduit, sans aucun commentaire ou texte explicatif.`; |
|
|
|
|
|
const parts = [ |
|
|
{ text: prompt }, |
|
|
{ text: initialHtml } |
|
|
]; |
|
|
|
|
|
const result = await model.generateContent({ contents: [{ role: "user", parts }] }); |
|
|
const response = result.response; |
|
|
|
|
|
generatedWordHtml = cleanApiResponse(response.text()); |
|
|
htmlOutputContainer.innerHTML = generatedWordHtml; |
|
|
|
|
|
if (generatedWordHtml) { |
|
|
downloadButton.style.display = 'inline-block'; |
|
|
generateReportButton.style.display = 'inline-block'; |
|
|
} |
|
|
|
|
|
} catch (error) { |
|
|
console.error('Erreur lors du processus:', error); |
|
|
htmlOutputContainer.innerHTML = `<p style="color:red;">Erreur: ${error.message}</p>`; |
|
|
} finally { |
|
|
loadingDiv.style.display = 'none'; |
|
|
convertToHtmlButton.disabled = false; |
|
|
} |
|
|
}); |
|
|
|
|
|
downloadButton.addEventListener('click', () => { |
|
|
const htmlToDownload = correctedHtml || generatedWordHtml; |
|
|
if (!htmlToDownload) return; |
|
|
|
|
|
const filename = correctedHtml ? 'document_corrige.doc' : 'document_converti.doc'; |
|
|
|
|
|
const fullHtml = ` |
|
|
<html xmlns:o='urn:schemas-microsoft-com:office:office' xmlns:w='urn:schemas-microsoft-com:office:word' xmlns='http://www.w3.org/TR/REC-html40'> |
|
|
<head><meta charset='utf-8'><title>Titre</title></head> |
|
|
<body>${htmlToDownload}<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=lufespi/tradu-o" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
|
|
</html>`; |
|
|
|
|
|
const blob = new Blob([fullHtml], { type: 'application/msword' }); |
|
|
const url = URL.createObjectURL(blob); |
|
|
const a = document.createElement('a'); |
|
|
a.href = url; |
|
|
a.download = filename; |
|
|
document.body.appendChild(a); |
|
|
a.click(); |
|
|
document.body.removeChild(a); |
|
|
URL.revokeObjectURL(url); |
|
|
}); |
|
|
|
|
|
generateReportButton.addEventListener('click', async () => { |
|
|
if (!generatedWordHtml) { |
|
|
alert("Aucun contenu à analyser. Veuillez d'abord convertir un document."); |
|
|
return; |
|
|
} |
|
|
|
|
|
generateReportButton.disabled = true; |
|
|
downloadButton.disabled = true; |
|
|
generateReportButton.textContent = 'Génération du rapport...'; |
|
|
|
|
|
try { |
|
|
const genAI = new GoogleGenerativeAI(API_KEY); |
|
|
const model = genAI.getGenerativeModel({ model: "gemini-1.5-flash-latest" }); |
|
|
|
|
|
|
|
|
const reportPrompt = `Analysez le texte contenu dans le code HTML suivant. Identifiez les phrases ou termes qui pourraient être améliorés dans la traduction. |
|
|
|
|
|
Pour chaque correction suggérée, formatez votre réponse EXACTEMENT comme suit, sur trois lignes : |
|
|
Ligne 1 : [Texte Original] - (IMPORTANT : incluez les balises HTML comme <em> ou <strong> si elles sont présentes dans le texte original) |
|
|
Ligne 2 : [Texte Corrigé] |
|
|
Ligne 3 : [Explication de la correction] |
|
|
|
|
|
Ne modifiez pas le code HTML global. Fournissez uniquement le rapport textuel en suivant ce format. Analysez le document entier.`; |
|
|
|
|
|
const fullPromptForReport = `${reportPrompt}\n\nVoici le code HTML à analyser:\n\n${generatedWordHtml}`; |
|
|
const parts = [{ text: fullPromptForReport }]; |
|
|
|
|
|
const result = await model.generateContent({ contents: [{ role: "user", parts }] }); |
|
|
const response = result.response; |
|
|
|
|
|
reportText = response.text(); |
|
|
|
|
|
previewHeader.textContent = 'Rapport de Traduction:'; |
|
|
htmlOutputContainer.innerHTML = reportText.replace(/\n/g, '<br>'); |
|
|
|
|
|
generateReportButton.style.display = 'none'; |
|
|
downloadButton.style.display = 'none'; |
|
|
backToHtmlButton.style.display = 'inline-block'; |
|
|
applySuggestionsButton.style.display = 'inline-block'; |
|
|
|
|
|
} catch (error) { |
|
|
console.error("Erreur lors de la génération du rapport:", error); |
|
|
alert("Erreur lors de la génération du rapport: " + error.message); |
|
|
} finally { |
|
|
generateReportButton.disabled = false; |
|
|
downloadButton.disabled = false; |
|
|
generateReportButton.textContent = '2. Générer un rapport de traduction'; |
|
|
} |
|
|
}); |
|
|
|
|
|
backToHtmlButton.addEventListener('click', () => { |
|
|
previewHeader.textContent = 'Aperçu HTML:'; |
|
|
htmlOutputContainer.innerHTML = generatedWordHtml; |
|
|
|
|
|
generateReportButton.style.display = 'inline-block'; |
|
|
downloadButton.style.display = 'inline-block'; |
|
|
backToHtmlButton.style.display = 'none'; |
|
|
applySuggestionsButton.style.display = 'none'; |
|
|
}); |
|
|
|
|
|
applySuggestionsButton.addEventListener('click', async () => { |
|
|
if (!generatedWordHtml || !reportText) { |
|
|
alert("Aucun rapport ou HTML original à utiliser. Une erreur est survenue."); |
|
|
return; |
|
|
} |
|
|
|
|
|
applySuggestionsButton.disabled = true; |
|
|
backToHtmlButton.disabled = true; |
|
|
applySuggestionsButton.textContent = 'Application en cours...'; |
|
|
loadingDiv.style.display = 'block'; |
|
|
|
|
|
try { |
|
|
const genAI = new GoogleGenerativeAI(API_KEY); |
|
|
const model = genAI.getGenerativeModel({ model: "gemini-1.5-flash-latest" }); |
|
|
|
|
|
|
|
|
const applyPrompt = ` |
|
|
En te basant sur le rapport d'analyse suivant : |
|
|
--- RAPPORT --- |
|
|
${reportText} |
|
|
--- FIN DU RAPPORT --- |
|
|
|
|
|
Modifie le code HTML original ci-dessous pour appliquer PRÉCISÉMENT ces suggestions. |
|
|
|
|
|
RÈGLE FONDAMENTALE : La structure HTML, y compris **TOUTES** les balises de mise en forme comme <em>, <i>, <strong>, etc., doit être conservée intacte. Appliquez les corrections de texte SANS supprimer ces balises. |
|
|
|
|
|
Exemple de comportement attendu : |
|
|
- HTML ORIGINAL : <p>Le statut est <em>en attente</em>.</p> |
|
|
- RAPPORT SUGGÈRE : "en attente" -> "en cours" |
|
|
- HTML CORRIGÉ ATTENDU : <p>Le statut est <em>en cours</em>.</p> |
|
|
|
|
|
--- HTML ORIGINAL --- |
|
|
${generatedWordHtml} |
|
|
--- FIN DU HTML ORIGINAL --- |
|
|
|
|
|
Retourne UNIQUEMENT le code HTML complet et corrigé, sans aucun commentaire ou texte explicatif supplémentaire. |
|
|
`; |
|
|
|
|
|
const parts = [{ text: applyPrompt }]; |
|
|
const result = await model.generateContent({ contents: [{ role: "user", parts }] }); |
|
|
const response = result.response; |
|
|
|
|
|
correctedHtml = cleanApiResponse(response.text()); |
|
|
|
|
|
previewHeader.textContent = 'Aperçu HTML (Version Corrigée):'; |
|
|
htmlOutputContainer.innerHTML = correctedHtml; |
|
|
|
|
|
applySuggestionsButton.style.display = 'none'; |
|
|
backToHtmlButton.style.display = 'none'; |
|
|
downloadButton.style.display = 'inline-block'; |
|
|
|
|
|
} catch (error) { |
|
|
console.error("Erreur lors de l'application des suggestions:", error); |
|
|
alert("Erreur lors de l'application des suggestions: " + error.message); |
|
|
htmlOutputContainer.innerHTML = reportText.replace(/\n/g, '<br>'); |
|
|
} finally { |
|
|
applySuggestionsButton.disabled = false; |
|
|
backToHtmlButton.disabled = false; |
|
|
applySuggestionsButton.textContent = "Appliquer les suggestions"; |
|
|
loadingDiv.style.display = 'none'; |
|
|
} |
|
|
}); |
|
|
|
|
|
</script> |
|
|
</head> |
|
|
<body> |
|
|
<div class="container"> |
|
|
<h1>Convertisseur de Document et Générateur de Rapport</h1> |
|
|
|
|
|
<p> |
|
|
Téléversez un document Word (.docx) pour le convertir en HTML et le traduire. |
|
|
</p> |
|
|
<div class="input-group"> |
|
|
<input type="file" id="fileInput" accept=".docx,application/vnd.openxmlformats-officedocument.wordprocessingml.document"> |
|
|
</div> |
|
|
|
|
|
<div class="input-group"> |
|
|
<label for="languageSelect">Langue cible :</label> |
|
|
<select id="languageSelect"> |
|
|
<option value="français" selected>Français</option> |
|
|
<option value="anglais">Anglais</option> |
|
|
<option value="espagnol">Espagnol</option> |
|
|
<option value="portugais">Portugais (Brésil)</option> |
|
|
<option value="allemand">Allemand</option> |
|
|
<option value="italien">Italien</option> |
|
|
<option value="japonais">Japonais</option> |
|
|
</select> |
|
|
</div> |
|
|
|
|
|
<button id="convertToHtmlButton">1. Convertir et Traduire</button> |
|
|
|
|
|
<div id="loading">Opération en cours, veuillez patienter...</div> |
|
|
|
|
|
<h2 id="previewHeader">Aperçu HTML:</h2> |
|
|
<div id="htmlOutputContainer"> |
|
|
<p>L'aperçu de l'HTML généré apparaîtra ici.</p> |
|
|
</div> |
|
|
|
|
|
<div style="text-align: right; margin-top: 20px;"> |
|
|
<button id="applySuggestionsButton" style="display:none;">Appliquer les suggestions</button> |
|
|
<button id="backToHtmlButton" style="display:none; margin-left: 10px;">Retour à l'aperçu HTML</button> |
|
|
<button id="generateReportButton" style="display:none; margin-left: 10px;">2. Générer un rapport de traduction</button> |
|
|
<button id="downloadButton" style="display:none;">Télécharger en .doc</button> |
|
|
</div> |
|
|
</div> |
|
|
</body> |
|
|
</html> |