Flasksite / templates /philosophie.html
Docfile's picture
Update templates/philosophie.html
3eb330f verified
raw
history blame
11.7 kB
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mariam AI - Assistant Philosophique</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/select2.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/select2.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/sweetalert2/11.7.3/sweetalert2.all.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/4.3.0/marked.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/locale/fr.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/sweetalert2/11.7.3/sweetalert2.min.css" rel="stylesheet">
<script src="https://cdn.tailwindcss.com"></script>
<style>
/* ... (tous les styles de votre fichier original restent ici) ... */
.collapsible { cursor: pointer; padding: 18px; width: 100%; border: none; text-align: left; outline: none; font-size: 15px; background-color: #f1f1f1; display: flex; justify-content: space-between; align-items: center; }
.prose { max-width: 100% !important; }
.prose p { margin-top: 1.25em; margin-bottom: 1.25em; line-height: 1.75; }
.prose ul { margin-top: 1.25em; margin-bottom: 1.25em; padding-left: 1.625em; }
#response .prose { color: #374151; word-wrap: break-word; overflow-wrap: break-word; hyphens: auto; }
.content { padding: 0 18px; display: none; overflow: hidden; background-color: white; }
.animate-fadeIn { animation: fadeIn 0.5s ease-out forwards; }
@keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
.select2-container--default .select2-selection--single { border: 1px solid #e5e7eb; border-radius: 0.75rem; height: auto; padding: 0.625rem 1rem; background-color: white; box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); display: flex; align-items: center; }
.select2-container--default .select2-selection--single .select2-selection__rendered { color: #374151; line-height: inherit; padding-right: 1.5rem; }
#image-preview { max-height: 200px; border-radius: 0.75rem; box-shadow: 0 4px 6px -1px rgba(0,0,0,.1), 0 2px 4px -2px rgba(0,0,0,.1); }
</style>
</head>
<body class="bg-gradient-to-br from-violet-50 to-indigo-50 min-h-screen">
<!-- Navbar -->
<nav class="bg-white/80 backdrop-blur-md border-b border-gray-200 fixed w-full z-50">
<!-- ... (contenu de la navbar inchangé) ... -->
</nav>
<!-- Main Content -->
<div class="pt-24 pb-12 px-4 sm:px-6 lg:px-8">
<div class="max-w-4xl mx-auto">
<div class="bg-white/80 backdrop-blur-md rounded-2xl shadow-xl border border-gray-100 overflow-hidden">
<div class="bg-gradient-to-r from-violet-600 to-indigo-600 p-6 text-white">
<h2 class="text-2xl font-bold">Gen'Dissertation</h2>
<p class="mt-2 opacity-90">Créez des dissertations et analyses philosophiques pertinentes et structurées</p>
</div>
<div class="p-8 space-y-8">
<!-- Type Selection -->
<div class="space-y-3">
<label class="block text-sm font-medium text-gray-700">Type de travail</label>
<select id="type-select" class="w-full rounded-xl border-gray-200 shadow-sm focus:border-violet-500 focus:ring-violet-500 appearance-none bg-white py-3 px-4 pr-10">
<option value="1">Sujet Type 1</option>
<option value="2">Sujet Type 2 (Citation)</option>
<option value="3">Analyse d'image</option>
</select>
</div>
<!-- Conteneur pour les champs de texte -->
<div id="text-input-container">
<!-- Course Selection -->
<div class="space-y-3">
<label class="block text-sm font-medium text-gray-700">Appuyer l'analyse sur un cours (Optionnel)</label>
<select id="course-select" class="w-full">
<option value="">Ne pas utiliser de cours</option>
</select>
</div>
<!-- Question Input -->
<div class="space-y-3 mt-8">
<label for="question" class="block text-sm font-medium text-gray-700">Sujet de dissertation</label>
<textarea id="question" rows="4" class="w-full rounded-xl border-gray-200 shadow-sm focus:border-violet-500 focus:ring-violet-500 resize-none bg-white py-3 px-4" placeholder="Saisissez votre sujet de dissertation..."></textarea>
</div>
</div>
<!-- Conteneur pour l'upload d'image -->
<div id="image-input-container" class="hidden">
<div class="space-y-3">
<label for="image-upload" class="block text-sm font-medium text-gray-700">Charger une image pour analyse</label>
<input type="file" id="image-upload" accept="image/jpeg, image/png, image/webp" class="block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-violet-50 file:text-violet-700 hover:file:bg-violet-100"/>
<div class="mt-4 flex justify-center">
<img id="image-preview" src="" alt="Aperçu de l'image" class="hidden"/>
</div>
</div>
</div>
<!-- Submit Button -->
<button id="submit-btn" class="w-full py-4 px-6 rounded-xl bg-gradient-to-r from-violet-600 to-indigo-600 text-white font-medium shadow-lg shadow-violet-200 hover:shadow-xl hover:shadow-violet-300 transform hover:-translate-y-0.5 transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-violet-500 focus:ring-offset-2">
Générer
</button>
<!-- Response Section -->
<div id="response" class="hidden mt-8 prose prose-violet max-w-none">
<div class="bg-gradient-to-r from-gray-50 to-white rounded-xl p-6 border border-gray-100">
<!-- La réponse en streaming sera insérée ici -->
</div>
</div>
<!-- Copy Button -->
<button id="copy-btn" class="hidden w-full py-3 ...">Copier</button>
<!-- Saved Dissertations Section -->
<div id="saved-dissertations" class="mt-8">
<!-- ... (section inchangée) ... -->
</div>
</div>
</div>
</div>
</div>
<!-- Bouton flottant DeepThink -->
<button id="deepthink-btn" class="fixed bottom-6 right-6 z-50 bg-indigo-600 text-white px-4 py-2 rounded-full shadow-lg hover:bg-indigo-700 focus:outline-none">
DeepThink
</button>
<script>
$(document).ready(function() {
// --- Initialisations ---
$('#course-select').select2({ /* ... options select2 ... */ });
marked.setOptions({ breaks: true, gfm: true });
moment.locale('fr');
const Toast = Swal.mixin({ toast: true, position: 'top-end', showConfirmButton: false, timer: 3000, timerProgressBar: true });
// --- Gestion de l'interface ---
$('#type-select').change(function() {
const type = $(this).val();
if (type === '3') { // Analyse d'image
$('#text-input-container').hide();
$('#image-input-container').show();
$('#deepthink-btn').hide();
$('#submit-btn span').text("Analyser l'image");
} else { // Dissertation texte
$('#text-input-container').show();
$('#image-input-container').hide();
$('#deepthink-btn').show();
$('#submit-btn span').text("Générer la dissertation");
}
}).trigger('change');
$('#image-upload').change(function(e) {
if (e.target.files && e.target.files[0]) {
const reader = new FileReader();
reader.onload = function(event) {
$('#image-preview').attr('src', event.target.result).removeClass('hidden');
}
reader.readAsDataURL(e.target.files[0]);
}
});
// --- Chargement des cours (inchangé) ---
// ...
// --- Logique de Génération en Streaming ---
async function handleStreamedGeneration(url, options) {
Swal.fire({ title: 'Génération en cours...', html: 'Veuillez patienter...', allowOutsideClick: false, showConfirmButton: false, didOpen: () => { Swal.showLoading() }});
const responseDiv = $('#response > div');
responseDiv.html('');
$('#response').removeClass('hidden');
$('#copy-btn').addClass('hidden');
let fullResponseText = '';
try {
const response = await fetch(url, options);
if (!response.ok) {
const errorText = await response.text();
throw new Error(errorText || `Erreur HTTP: ${response.status}`);
}
const reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { value, done } = await reader.read();
if (done) break;
const chunk = decoder.decode(value, { stream: true });
fullResponseText += chunk;
responseDiv.html(marked.parse(fullResponseText));
window.scrollTo(0, document.body.scrollHeight);
}
Swal.close();
$('#copy-btn').removeClass('hidden');
Toast.fire({ icon: 'success', title: 'Génération terminée !' });
saveDissertation($('#question').val().trim() || "Analyse d'image", fullResponseText);
} catch (error) {
console.error('Erreur de streaming:', error);
Swal.fire({ icon: 'error', title: 'Erreur', text: error.message });
}
}
// --- Gestion des Clics ---
$('#submit-btn, #deepthink-btn').click(function() {
const type = $('#type-select').val();
const isDeepThink = $(this).attr('id') === 'deepthink-btn';
if (type === '3') { // Analyse d'image
const imageFile = $('#image-upload')[0].files[0];
if (!imageFile) {
Swal.fire('Erreur', 'Veuillez sélectionner une image.', 'error');
return;
}
const formData = new FormData();
formData.append('image', imageFile);
handleStreamedGeneration('/stream_philo_image', { method: 'POST', body: formData });
} else { // Dissertation texte
const question = $('#question').val().trim();
if (!question) {
Swal.fire('Erreur', 'Veuillez saisir un sujet.', 'error');
return;
}
const data = {
question: question,
type: type,
courseId: $('#course-select').val() || null
};
const url = isDeepThink ? '/stream_philo_deepthink' : '/stream_philo';
handleStreamedGeneration(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
}
});
// --- Fonctions de sauvegarde et copie (inchangées) ---
function saveDissertation(title, content) { /* ... */ }
function deleteDissertation(index) { /* ... */ }
function updateSavedDissertationsList() { /* ... */ }
$('#copy-btn').click(function() { /* ... */ });
updateSavedDissertationsList();
});
</script>
</body>
</html>