Mariam-cards / templates /index.html
Docfile's picture
Update templates/index.html
078c480 verified
raw
history blame
24.3 kB
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Résolveur d'exercices</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.0/es5/tex-mml-chtml.js"></script>
<style>
:root {
--primary-color: #4361ee;
--secondary-color: #3f37c9;
--accent-color: #f72585;
--text-color: #333;
--light-color: #f8f9fa;
--dark-color: #212529;
--success-color: #4cc9a0;
--border-radius: 8px;
--box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
--transition: all 0.3s ease;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #f5f7fa 0%, #e4e8f0 100%);
color: var(--text-color);
line-height: 1.6;
min-height: 100vh;
padding: 20px;
}
header {
text-align: center;
margin-bottom: 2rem;
animation: fadeIn 1s;
}
h1 {
color: var(--primary-color);
font-size: 2.2rem;
margin-bottom: 0.5rem;
}
.subheading {
color: var(--secondary-color);
font-size: 1.1rem;
font-weight: 500;
}
.container {
max-width: 800px;
margin: 0 auto;
background-color: white;
border-radius: var(--border-radius);
box-shadow: var(--box-shadow);
overflow: hidden;
}
.tabs {
display: flex;
background-color: var(--light-color);
border-bottom: 1px solid #e1e5ea;
}
.tab {
flex: 1;
padding: 15px;
text-align: center;
cursor: pointer;
transition: var(--transition);
font-weight: 600;
color: var(--text-color);
position: relative;
overflow: hidden;
}
.tab.active {
background-color: white;
color: var(--primary-color);
}
.tab:after {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 3px;
background-color: var(--primary-color);
transform: scaleX(0);
transition: transform 0.3s ease;
}
.tab.active:after {
transform: scaleX(1);
}
.tab-content {
padding: 30px;
display: none;
}
.tab-content.active {
display: block;
animation: fadeIn 0.5s;
}
.upload-container {
text-align: center;
padding: 20px;
border: 2px dashed #d1d5db;
border-radius: var(--border-radius);
margin-bottom: 20px;
transition: var(--transition);
cursor: pointer;
}
.upload-container:hover {
border-color: var(--primary-color);
background-color: rgba(67, 97, 238, 0.05);
}
.upload-icon {
font-size: 3rem;
color: var(--primary-color);
margin-bottom: 15px;
}
.upload-text {
margin-bottom: 15px;
font-size: 1.1rem;
}
.upload-input {
display: none;
}
.btn {
display: inline-block;
background-color: var(--primary-color);
color: white;
padding: 12px 25px;
border: none;
border-radius: var(--border-radius);
cursor: pointer;
font-size: 1rem;
font-weight: 600;
transition: var(--transition);
text-align: center;
text-decoration: none;
margin: 10px 0;
}
.btn:hover {
background-color: var(--secondary-color);
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(67, 97, 238, 0.3);
}
.btn-full {
width: 100%;
}
.btn-secondary {
background-color: var(--light-color);
color: var(--text-color);
}
.btn-secondary:hover {
background-color: #e2e6ea;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
}
.btn-accent {
background-color: var(--accent-color);
}
.btn-accent:hover {
background-color: #e5147a;
box-shadow: 0 5px 15px rgba(247, 37, 133, 0.3);
}
.image-preview {
max-width: 100%;
height: auto;
margin: 20px 0;
border-radius: var(--border-radius);
box-shadow: var(--box-shadow);
display: none;
}
.result-container {
margin-top: 30px;
padding: 20px;
background-color: var(--light-color);
border-radius: var(--border-radius);
display: none;
}
.loading {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 30px;
display: none;
}
.loading-text {
margin-top: 15px;
font-weight: 600;
color: var(--primary-color);
}
.thinking-indicator {
display: inline-block;
margin-left: 10px;
font-size: 1.5rem;
color: var(--primary-color);
animation: pulse 1.5s infinite;
}
@keyframes pulse {
0% { transform: scale(0.95); opacity: 0.7; }
50% { transform: scale(1.05); opacity: 1; }
100% { transform: scale(0.95); opacity: 0.7; }
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.features {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
margin: 30px 0;
}
.feature {
text-align: center;
padding: 20px;
background-color: white;
border-radius: var(--border-radius);
box-shadow: var(--box-shadow);
transition: var(--transition);
}
.feature:hover {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
}
.feature-icon {
font-size: 2.5rem;
color: var(--primary-color);
margin-bottom: 15px;
}
.feature-title {
font-size: 1.2rem;
margin-bottom: 10px;
font-weight: 600;
}
.feature-desc {
color: #666;
font-size: 0.95rem;
}
footer {
text-align: center;
margin-top: 3rem;
color: #6c757d;
font-size: 0.9rem;
}
/* Mobile responsive styles */
@media (max-width: 768px) {
body {
padding: 10px;
}
h1 {
font-size: 1.8rem;
}
.subheading {
font-size: 1rem;
}
.container {
border-radius: var(--border-radius);
}
.tab {
padding: 12px 5px;
font-size: 0.9rem;
}
.tab-content {
padding: 20px 15px;
}
.upload-icon {
font-size: 2.5rem;
}
.upload-text {
font-size: 1rem;
}
.btn {
padding: 10px 20px;
font-size: 0.95rem;
}
.features {
grid-template-columns: 1fr;
}
}
</style>
</head>
<body>
<header>
<h1>SolveMath.AI</h1>
<p class="subheading">Résolution avancée d'exercices par Intelligence Artificielle</p>
</header>
<div class="container">
<div class="tabs">
<div class="tab active" data-tab="standard">Standard</div>
<div class="tab" data-tab="pro">Pro (Réflexion)</div>
</div>
<div class="tab-content active" id="standard-content">
<p>Utilisez notre IA standard pour résoudre rapidement vos exercices.</p>
<div class="upload-container" id="standard-upload">
<i class="fas fa-cloud-upload-alt upload-icon"></i>
<p class="upload-text">Cliquez ou déposez une image de votre exercice</p>
<input type="file" id="standard-file" class="upload-input" accept="image/*">
</div>
<img id="standard-preview" class="image-preview">
<button id="standard-solve" class="btn btn-full" disabled>Résoudre l'exercice</button>
<div id="standard-loading" class="loading">
<i class="fas fa-cog fa-spin fa-2x"></i>
<p class="loading-text">Analyse en cours... <span id="standard-thinking-status"></span></p>
</div>
<div id="standard-result" class="result-container">
<h3>Solution :</h3>
<div id="standard-solution"></div>
</div>
</div>
<div class="tab-content" id="pro-content">
<p>Mode Pro : utilise une réflexion approfondie pour résoudre des exercices complexes.</p>
<div class="upload-container" id="pro-upload">
<i class="fas fa-cloud-upload-alt upload-icon"></i>
<p class="upload-text">Cliquez ou déposez une image de votre exercice complexe</p>
<input type="file" id="pro-file" class="upload-input" accept="image/*">
</div>
<img id="pro-preview" class="image-preview">
<button id="pro-solve" class="btn btn-full btn-accent" disabled>Résoudre avec réflexion approfondie</button>
<div id="pro-loading" class="loading">
<i class="fas fa-brain fa-2x"></i>
<p class="loading-text">Analyse approfondie... <span id="pro-thinking-status"></span></p>
</div>
<div id="pro-result" class="result-container">
<h3>Solution détaillée :</h3>
<div id="pro-solution"></div>
</div>
</div>
</div>
<div class="features">
<div class="feature">
<i class="fas fa-bolt feature-icon"></i>
<h3 class="feature-title">Rapide</h3>
<p class="feature-desc">Solutions instantanées pour les exercices simples</p>
</div>
<div class="feature">
<i class="fas fa-brain feature-icon"></i>
<p class="feature-title">Intelligent</p>
<p class="feature-desc">Résolution détaillée de problèmes complexes</p>
</div>
<div class="feature">
<i class="fas fa-mobile-alt feature-icon"></i>
<p class="feature-title">Mobile</p>
<p class="feature-desc">Fonctionne parfaitement sur tous les appareils</p>
</div>
</div>
<footer>
<p>&copy; 2025 SolveMath.AI - Propulsé par l'intelligence artificielle</p>
</footer>
<script>
// Tab switching functionality
const tabs = document.querySelectorAll('.tab');
const tabContents = document.querySelectorAll('.tab-content');
tabs.forEach(tab => {
tab.addEventListener('click', () => {
const tabId = tab.getAttribute('data-tab');
// Update active tab
tabs.forEach(t => t.classList.remove('active'));
tab.classList.add('active');
// Update active content
tabContents.forEach(content => content.classList.remove('active'));
document.getElementById(`${tabId}-content`).classList.add('active');
});
});
// File upload functionality - Standard mode
const standardUpload = document.getElementById('standard-upload');
const standardFile = document.getElementById('standard-file');
const standardPreview = document.getElementById('standard-preview');
const standardSolve = document.getElementById('standard-solve');
const standardLoading = document.getElementById('standard-loading');
const standardResult = document.getElementById('standard-result');
const standardSolution = document.getElementById('standard-solution');
const standardThinkingStatus = document.getElementById('standard-thinking-status');
standardUpload.addEventListener('click', () => standardFile.click());
standardFile.addEventListener('change', (e) => {
if (e.target.files.length > 0) {
const file = e.target.files[0];
const reader = new FileReader();
reader.onload = (e) => {
standardPreview.src = e.target.result;
standardPreview.style.display = 'block';
standardSolve.disabled = false;
};
reader.readAsDataURL(file);
}
});
// File upload functionality - Pro mode
const proUpload = document.getElementById('pro-upload');
const proFile = document.getElementById('pro-file');
const proPreview = document.getElementById('pro-preview');
const proSolve = document.getElementById('pro-solve');
const proLoading = document.getElementById('pro-loading');
const proResult = document.getElementById('pro-result');
const proSolution = document.getElementById('pro-solution');
const proThinkingStatus = document.getElementById('pro-thinking-status');
proUpload.addEventListener('click', () => proFile.click());
proFile.addEventListener('change', (e) => {
if (e.target.files.length > 0) {
const file = e.target.files[0];
const reader = new FileReader();
reader.onload = (e) => {
proPreview.src = e.target.result;
proPreview.style.display = 'block';
proSolve.disabled = false;
};
reader.readAsDataURL(file);
}
});
// Drag and drop functionality
['standard', 'pro'].forEach(mode => {
const uploadContainer = document.getElementById(`${mode}-upload`);
const fileInput = document.getElementById(`${mode}-file`);
const preview = document.getElementById(`${mode}-preview`);
const solveBtn = document.getElementById(`${mode}-solve`);
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
uploadContainer.addEventListener(eventName, preventDefaults, false);
});
function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}
['dragenter', 'dragover'].forEach(eventName => {
uploadContainer.addEventListener(eventName, () => {
uploadContainer.classList.add('highlight');
}, false);
});
['dragleave', 'drop'].forEach(eventName => {
uploadContainer.addEventListener(eventName, () => {
uploadContainer.classList.remove('highlight');
}, false);
});
uploadContainer.addEventListener('drop', (e) => {
const file = e.dataTransfer.files[0];
if (file && file.type.startsWith('image/')) {
fileInput.files = e.dataTransfer.files;
const reader = new FileReader();
reader.onload = (e) => {
preview.src = e.target.result;
preview.style.display = 'block';
solveBtn.disabled = false;
};
reader.readAsDataURL(file);
}
}, false);
});
// Solve functionality - Standard
standardSolve.addEventListener('click', () => {
if (!standardFile.files.length) return;
const formData = new FormData();
formData.append('image', standardFile.files[0]);
standardSolve.disabled = true;
standardLoading.style.display = 'flex';
standardResult.style.display = 'none';
standardSolution.innerHTML = '';
const eventSource = new EventSource('/solved?' + new URLSearchParams({
timestamp: new Date().getTime()
}));
let accumulatedText = '';
eventSource.addEventListener('message', function(event) {
const data = JSON.parse(event.data);
if (data.mode === 'thinking') {
standardThinkingStatus.innerHTML = '<span class="thinking-indicator">🤔</span>';
}
if (data.mode === 'answering') {
standardThinkingStatus.innerHTML = '';
}
if (data.content) {
accumulatedText += data.content;
standardSolution.innerHTML = accumulatedText;
standardResult.style.display = 'block';
// Render LaTeX if present
if (typeof MathJax !== 'undefined') {
MathJax.typesetPromise([standardSolution]);
}
}
if (data.error) {
standardSolution.innerHTML = `<p class="error">Erreur: ${data.error}</p>`;
standardResult.style.display = 'block';
eventSource.close();
standardLoading.style.display = 'none';
standardSolve.disabled = false;
}
});
eventSource.addEventListener('error', function() {
eventSource.close();
standardLoading.style.display = 'none';
standardSolve.disabled = false;
if (!accumulatedText) {
standardSolution.innerHTML = '<p class="error">Une erreur est survenue lors de la communication avec le serveur.</p>';
standardResult.style.display = 'block';
}
});
// Actual fetch to backend
fetch('/solved', {
method: 'POST',
body: formData
}).catch(error => {
console.error('Error:', error);
eventSource.close();
standardLoading.style.display = 'none';
standardSolve.disabled = false;
standardSolution.innerHTML = '<p class="error">Une erreur est survenue lors de l\'envoi de l\'image.</p>';
standardResult.style.display = 'block';
});
});
// Solve functionality - Pro
proSolve.addEventListener('click', () => {
if (!proFile.files.length) return;
const formData = new FormData();
formData.append('image', proFile.files[0]);
proSolve.disabled = true;
proLoading.style.display = 'flex';
proResult.style.display = 'none';
proSolution.innerHTML = '';
const eventSource = new EventSource('/solve?' + new URLSearchParams({
timestamp: new Date().getTime()
}));
let accumulatedText = '';
eventSource.addEventListener('message', function(event) {
const data = JSON.parse(event.data);
if (data.mode === 'thinking') {
proThinkingStatus.innerHTML = '<span class="thinking-indicator">💭</span>';
}
if (data.mode === 'answering') {
proThinkingStatus.innerHTML = '';
}
if (data.content) {
accumulatedText += data.content;
proSolution.innerHTML = accumulatedText;
proResult.style.display = 'block';
// Render LaTeX if present
if (typeof MathJax !== 'undefined') {
MathJax.typesetPromise([proSolution]);
}
}
if (data.error) {
proSolution.innerHTML = `<p class="error">Erreur: ${data.error}</p>`;
proResult.style.display = 'block';
eventSource.close();
proLoading.style.display = 'none';
proSolve.disabled = false;
}
});
eventSource.addEventListener('error', function() {
eventSource.close();
proLoading.style.display = 'none';
proSolve.disabled = false;
if (!accumulatedText) {
proSolution.innerHTML = '<p class="error">Une erreur est survenue lors de la communication avec le serveur.</p>';
proResult.style.display = 'block';
}
});
// Actual fetch to backend
fetch('/solve', {
method: 'POST',
body: formData
}).catch(error => {
console.error('Error:', error);
eventSource.close();
proLoading.style.display = 'none';
proSolve.disabled = false;
proSolution.innerHTML = '<p class="error">Une erreur est survenue lors de l\'envoi de l\'image.</p>';
proResult.style.display = 'block';
});
});
// Support for drag and drop highlight styling
document.querySelectorAll('.upload-container').forEach(container => {
container.addEventListener('dragenter', () => {
container.style.borderColor = 'var(--primary-color)';
container.style.backgroundColor = 'rgba(67, 97, 238, 0.05)';
});
container.addEventListener('dragleave', () => {
container.style.borderColor = '#d1d5db';
container.style.backgroundColor = '';
});
});
</script>
</body>
</html>