Mariam-generale / templates /generale.html
Docfile's picture
Create templates/generale.html
003c135 verified
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Question Générale</title>
<!-- Style de secours pour masquer les éléments dès le début -->
<style>
.hidden { display: none !important; }
</style>
<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Marked (Markdown) -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/4.0.2/marked.min.js" defer></script>
<!-- Font Awesome -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css" />
<!-- SweetAlert2 -->
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11" defer></script>
<!-- Polyfill -->
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6" defer></script>
<!-- Anime.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js" defer></script>
<!-- Configuration de MathJax -->
<script>
window.MathJax = {
tex: {
inlineMath: [['$', '$'], ['\\(', '\\)']],
displayMath: [['$$', '$$'], ['\\[', '\\]']],
processEscapes: true
},
options: {
skipHtmlTags: ['script', 'noscript', 'style', 'textarea', 'pre']
},
startup: {
pageReady: () => {
return MathJax.startup.defaultPageReady().then(() => {
console.log('MathJax initial typesetting complete');
});
}
}
};
</script>
<!-- MathJax -->
<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js" defer></script>
<style>
:root {
--primary-color: #008cba;
--background-color: #f0f8ff;
--animation-timing: 0.3s;
}
body {
margin: 0;
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Arial, sans-serif;
background-color: var(--background-color);
min-height: 100vh;
padding: 20px;
box-sizing: border-box;
overflow-x: hidden;
}
.navbar {
background-color: var(--primary-color);
color: white;
padding: 15px;
width: 100%;
text-align: center;
font-size: 24px;
font-weight: bold;
position: fixed;
top: 0;
left: 0;
z-index: 1000;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
animation: slideDown 0.5s ease-out;
}
.container {
margin-top: 80px;
max-width: 800px;
background-color: white;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
padding: 20px;
animation: fadeInScale 0.5s forwards;
}
.button {
background-color: var(--primary-color);
color: white;
padding: 15px;
border: none;
border-radius: 8px;
font-size: 16px;
text-align: center;
cursor: pointer;
position: relative;
overflow: hidden;
transform: translateZ(0);
will-change: transform;
transition: all var(--animation-timing) ease;
}
.button:hover {
transform: scale(1.05) translateY(-2px);
box-shadow: 0 10px 20px rgba(0,0,0,0.2);
}
.button i {
margin-right: 10px;
transition: transform var(--animation-timing) ease;
}
.input-field {
width: 100%;
padding: 12px;
border: 2px solid var(--primary-color);
border-radius: 8px;
margin-bottom: 15px;
transition: all var(--animation-timing) ease;
}
.input-field:focus {
outline: none;
box-shadow: 0 0 0 3px rgba(0,140,186,0.2);
}
#response {
background-color: #f8f9fa;
border-radius: 8px;
padding: 15px;
margin-top: 20px;
animation: fadeIn 0.5s ease-out;
}
#loader {
display: flex;
justify-content: center;
align-items: center;
margin: 20px 0;
}
@keyframes fadeInScale {
0% {
opacity: 0;
transform: scale(0.5);
}
100% {
opacity: 1;
transform: scale(1);
}
}
@keyframes slideDown {
from { transform: translateY(-100%); }
to { transform: translateY(0); }
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.url-item {
background-color: #f0f8ff;
padding: 10px;
border-radius: 6px;
margin-bottom: 8px;
display: flex;
align-items: center;
animation: fadeIn 0.3s ease-out;
}
</style>
</head>
<body>
<div class="navbar">Mariam AI</div>
<div class="container mx-auto">
<!-- En-tête -->
<div class="flex flex-col md:flex-row md:justify-between items-start md:items-center mb-6 space-y-4 md:space-y-0">
<h1 class="text-3xl font-bold text-gray-800">Poser une question générale</h1>
<button onclick="showInfo()" class="button">
<i class="fas fa-info-circle"></i> Info
</button>
</div>
<!-- Zone de question -->
<div class="mb-6">
<label for="questionInput" class="block mb-2 text-lg font-medium text-gray-700">Votre question :</label>
<textarea id="questionInput" class="input-field" rows="4" placeholder="Entrez votre question ici..."></textarea>
</div>
<!-- Zone d'ajout d'URLs -->
<div class="mb-6">
<label for="urlInput" class="block mb-2 text-lg font-medium text-gray-700">URLs (optionnel) :</label>
<div class="flex">
<input type="text" id="urlInput" class="input-field" placeholder="Entrez une URL" />
<button onclick="addUrl()" class="button ml-2">
<i class="fas fa-plus"></i> Ajouter
</button>
</div>
<div id="urlList" class="mt-2 space-y-2"></div>
</div>
<!-- Zone d'ajout de fichiers -->
<div class="mb-6">
<label for="fileUpload" class="block mb-2 text-lg font-medium text-gray-700">Fichiers (optionnel) :</label>
<input type="file" id="fileUpload" class="input-field" multiple />
</div>
<!-- Bouton de soumission -->
<button onclick="submitQuestion()" class="button w-full">
<i class="fas fa-paper-plane"></i> Soumettre
</button>
<!-- Loader -->
<div id="loader" class="hidden">
<div class="animate-spin rounded-full h-12 w-12 border-t-4 border-b-4 border-blue-500"></div>
<p class="ml-2 text-gray-600">Chargement en cours...</p>
</div>
<!-- Affichage de la réponse -->
<div id="response" class="hidden"></div>
<!-- Bouton pour copier la réponse -->
<div id="copyResponseContainer" class="hidden mt-4">
<button onclick="copyResponse()" class="button w-full">
<i class="fas fa-copy"></i> Copier la réponse
</button>
</div>
</div>
<script>
function showInfo() {
Swal.fire({
title: 'Information',
html: `
<p class="mb-2">Ce formulaire vous permet de poser des questions générales.</p>
<p class="mb-2">Vous pouvez également ajouter des URLs et des fichiers pour fournir plus de contexte à votre question.</p>
<p class="mb-2">La réponse sera formatée en Markdown et peut inclure des équations LaTeX.</p>
<p>Si vous souhaitez résoudre vos exercices de mathématiques ici, signalez-le à Mariam pour une réponse en LaTeX.</p>
`,
icon: 'info',
confirmButtonText: 'Compris'
});
}
function addUrl() {
const urlInput = document.getElementById('urlInput');
const urlList = document.getElementById('urlList');
const url = urlInput.value.trim();
if (url) {
const urlItem = document.createElement('div');
urlItem.className = 'url-item flex items-center bg-gray-200 p-2 rounded-lg shadow-sm';
urlItem.innerHTML = `
<span class="flex-grow truncate">${url}</span>
<button onclick="removeUrl(this)" class="ml-2 text-red-500 hover:text-red-700">
<i class="fas fa-times"></i>
</button>
`;
urlList.appendChild(urlItem);
urlInput.value = '';
}
}
function removeUrl(button) {
const urlItem = button.closest('.url-item');
if(urlItem) urlItem.remove();
}
async function submitQuestion() {
const question = document.getElementById('questionInput').value.trim();
if (!question) return;
const loader = document.getElementById('loader');
const responseDiv = document.getElementById('response');
const copyResponseContainer = document.getElementById('copyResponseContainer');
// Afficher le loader et réinitialiser la zone de réponse
loader.classList.remove('hidden');
responseDiv.classList.remove('hidden');
responseDiv.innerHTML = '';
responseDiv.classList.add('opacity-0');
copyResponseContainer.classList.add('hidden');
const formData = new FormData();
formData.append('question', question);
// Récupération des URLs
document.querySelectorAll('#urlList .url-item').forEach(item => {
formData.append('urls', item.querySelector('span').textContent);
});
// Récupération des fichiers
Array.from(document.getElementById('fileUpload').files).forEach(file => {
formData.append('files', file);
});
try {
const response = await fetch('/submit', {
method: 'POST',
body: formData
});
const data = await response.json();
loader.classList.add('hidden');
responseDiv.classList.remove('opacity-0');
if (data.error) {
responseDiv.innerHTML = `<p class="text-red-600">Erreur : ${data.error}</p>`;
} else {
const htmlContent = marked.parse(data.response);
responseDiv.innerHTML = htmlContent;
copyResponseContainer.classList.remove('hidden');
// Rendu de LaTeX avec MathJax
await MathJax.typesetPromise([responseDiv]);
console.log('LaTeX rendu avec succès');
}
} catch (error) {
loader.classList.add('hidden');
responseDiv.innerHTML = `<p class="text-red-600">Erreur : ${error.message}</p>`;
responseDiv.classList.remove('opacity-0');
}
}
function copyResponse() {
const responseDiv = document.getElementById('response');
const text = responseDiv.innerText;
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text)
.then(() => {
Swal.fire({
icon: 'success',
title: 'Copié !',
text: 'La réponse a été copiée dans le presse-papiers.',
showConfirmButton: false,
timer: 1500
});
})
.catch(err => {
console.error('Erreur lors de la copie avec Clipboard API:', err);
fallbackCopyTextToClipboard(text);
});
} else {
fallbackCopyTextToClipboard(text);
}
}
function fallbackCopyTextToClipboard(text) {
const textArea = document.createElement("textarea");
textArea.value = text;
// Éviter le scroll et positionner en dehors de l'écran
textArea.style.top = "0";
textArea.style.left = "0";
textArea.style.position = "fixed";
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
try {
const successful = document.execCommand('copy');
if (successful) {
Swal.fire({
icon: 'success',
title: 'Copié !',
text: 'La réponse a été copiée dans le presse-papiers.',
showConfirmButton: false,
timer: 1500
});
} else {
console.error('Erreur lors de la copie avec execCommand');
}
} catch (err) {
console.error('Erreur lors de la copie:', err);
}
document.body.removeChild(textArea);
}
</script>
</body>
</html>