File size: 6,338 Bytes
040db21 37619a6 040db21 c0834c0 040db21 c0834c0 0d2d16d c0834c0 0d2d16d c0834c0 0d2d16d c0834c0 0d2d16d c0834c0 0d2d16d c0834c0 0abab50 c0834c0 0abab50 c0834c0 0d2d16d c0834c0 0d2d16d c0834c0 37619a6 c0834c0 040db21 0d2d16d |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mariam AI</title>
<!-- Intégration de Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Intégration d'Animate.css pour les animations -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"/>
<style>
/* Loader personnalisé */
.loader {
border-top-color: #3498db;
animation: spin 1s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
</style>
</head>
<body class="bg-gradient-to-r from-blue-500 to-purple-600 min-h-screen flex items-center justify-center">
<div class="bg-white rounded-xl shadow-2xl overflow-hidden w-full max-w-4xl">
<!-- En-tête -->
<header class="bg-gradient-to-r from-purple-600 to-blue-500 p-6 flex justify-between items-center">
<h1 class="text-white text-3xl font-bold">Mariam AI</h1>
<div class="flex space-x-4">
<label class="flex items-center text-white">
<input type="checkbox" id="webSearchToggle" class="mr-2">
Activer la recherche web
</label>
<button onclick="clearChat()" class="bg-red-500 hover:bg-red-600 text-white px-4 py-2 rounded transition duration-200">
Effacer le chat
</button>
</div>
</header>
<!-- Contenu principal -->
<main class="p-6 flex flex-col h-96">
<!-- Upload de fichier -->
<div class="mb-4 flex items-center">
<input type="file" id="fileUpload" class="hidden" accept=".jpg,.jpeg,.png,.pdf,.txt,.mp3,.mp4">
<label for="fileUpload" class="cursor-pointer bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded transition duration-200">
Télécharger un fichier
</label>
<span id="fileName" class="ml-2 text-gray-600"></span>
</div>
<!-- Zone des messages -->
<div id="chatMessages" class="flex-1 overflow-y-auto space-y-4 mb-4">
{% for message in messages %}
<div class="flex {% if message.role == 'user' %}justify-end{% else %}justify-start{% endif %} animate__animated animate__fadeIn">
<div class="max-w-3/4 p-3 rounded-lg {% if message.role == 'user' %}bg-blue-500 text-white{% else %}bg-gray-200 text-gray-800{% endif %}">
{{ message.content }}
</div>
</div>
{% endfor %}
</div>
<!-- Loader animé -->
<div id="loader" class="hidden flex justify-center my-4">
<div class="loader border-8 border-t-8 border-gray-200 rounded-full h-12 w-12"></div>
</div>
<!-- Zone de saisie -->
<div class="border-t pt-4">
<div class="flex space-x-4">
<input type="text" id="messageInput" class="flex-1 border rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="Écrivez votre message...">
<button onclick="sendMessage()" class="bg-blue-500 hover:bg-blue-600 text-white px-6 py-2 rounded-lg transition duration-200 transform hover:scale-105">
Envoyer
</button>
</div>
</div>
</main>
</div>
<!-- Scripts -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/4.0.2/marked.min.js"></script>
<script>
const messageInput = document.getElementById('messageInput');
const chatMessages = document.getElementById('chatMessages');
const webSearchToggle = document.getElementById('webSearchToggle');
const fileUpload = document.getElementById('fileUpload');
const fileName = document.getElementById('fileName');
const loader = document.getElementById('loader');
function addMessage(content, isUser = false) {
const messageDiv = document.createElement('div');
messageDiv.className = `flex ${isUser ? 'justify-end' : 'justify-start'} animate__animated animate__fadeIn`;
const innerDiv = document.createElement('div');
innerDiv.className = `max-w-3/4 p-3 rounded-lg ${isUser ? 'bg-blue-500 text-white' : 'bg-gray-200 text-gray-800'}`;
innerDiv.innerHTML = marked.parse(content);
messageDiv.appendChild(innerDiv);
chatMessages.appendChild(messageDiv);
chatMessages.scrollTop = chatMessages.scrollHeight;
}
async function sendMessage() {
const message = messageInput.value.trim();
if (!message) return;
addMessage(message, true);
messageInput.value = '';
loader.classList.remove('hidden'); // Afficher le loader
try {
const response = await fetch('/send_message', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
message: message,
web_search: webSearchToggle.checked
})
});
const data = await response.json();
loader.classList.add('hidden'); // Masquer le loader
if (data.error) {
addMessage(`Erreur: ${data.error}`);
} else {
addMessage(data.response);
}
} catch (error) {
loader.classList.add('hidden');
addMessage(`Erreur: ${error.message}`);
}
}
messageInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
sendMessage();
}
});
fileUpload.addEventListener('change', async (e) => {
const file = e.target.files[0];
if (!file) return;
fileName.textContent = file.name;
const formData = new FormData();
formData.append('file', file);
try {
const response = await fetch('/upload', {
method: 'POST',
body: formData
});
const data = await response.json();
if (data.error) {
alert(`Erreur: ${data.error}`);
} else {
addMessage(`Fichier téléchargé: ${file.name}`);
}
} catch (error) {
alert(`Erreur: ${error.message}`);
}
});
async function clearChat() {
try {
await fetch('/clear_chat', { method: 'POST' });
chatMessages.innerHTML = '';
location.reload();
} catch (error) {
alert(`Erreur: ${error.message}`);
}
}
</script>
</body>
</html> |