const chatbox = document.getElementById('chatbox'); const messageInput = document.getElementById('message-input'); const sendButton = document.getElementById('send-button'); // --- addMessage function (inchangée) --- function addMessage(role, text) { const messageDiv = document.createElement('div'); messageDiv.classList.add('message', role === 'user' ? 'user-message' : 'assistant-message'); messageDiv.innerHTML = text.replace(/\n/g, '
'); chatbox.appendChild(messageDiv); chatbox.scrollTop = chatbox.scrollHeight; } // --- processSSEBuffer function (inchangée - version Méthode 1) --- function processSSEBuffer(buffer, targetDiv, currentResponseAccumulated) { console.log("Processing buffer:", buffer); // LOG AJOUTÉ let messages = buffer.split('\n\n'); let incomplete = buffer.endsWith('\n\n') ? '' : messages.pop(); let newResponsePart = ''; messages.forEach(message => { if (!message.trim()) return; let eventType = 'message'; let dataLines = []; message.split('\n').forEach(line => { if (line.startsWith('event: ')) { eventType = line.substring(7).trim(); } else if (line.startsWith('data: ')) { dataLines.push(line.substring(6)); } }); let data = dataLines.join('\n'); console.log(`--> SSE Event Parsed: ${eventType}, Data: ${data.substring(0, 100)}...`); // LOG AJOUTÉ if (eventType === 'message') { if (targetDiv.querySelector('.thinking')) { console.log("Replacing 'thinking' indicator"); // LOG AJOUTÉ targetDiv.innerHTML = ''; } newResponsePart += data; } else if (eventType === 'end') { console.log("Fin de stream détectée (event: end)"); // LOG AJOUTÉ sendButton.disabled = false; } else if (eventType === 'error') { console.error("Erreur SSE du serveur:", data); // LOG AJOUTÉ currentResponseAccumulated += `
خطأ من الخادم: ${data}`; sendButton.disabled = false; } }); const updatedResponse = currentResponseAccumulated + newResponsePart; // Limiter la fréquence de mise à jour de innerHTML si beaucoup de petits chunks targetDiv.innerHTML = updatedResponse.replace(/\n/g, '
'); chatbox.scrollTop = chatbox.scrollHeight; // console.log("Updated Response:", updatedResponse.substring(0, 100) + "..."); // Optionnel: peut être très verbeux return { incomplete: incomplete, updatedResponse: updatedResponse }; } // --- adjustTextareaHeight function (inchangée) --- function adjustTextareaHeight() { /* ... */ } // --- askQuestion function (avec plus de logs) --- async function askQuestion() { console.log("askQuestion called"); // LOG AJOUTÉ const question = messageInput.value.trim(); if (!question) { console.log("Question is empty, aborting."); // LOG AJOUTÉ return; } addMessage('user', question); messageInput.value = ''; sendButton.disabled = true; adjustTextareaHeight(); // Réajuste après vidage console.log("User message added, button disabled."); // LOG AJOUTÉ // Crée un placeholder pour la réponse de l'assistant const assistantMessageDiv = document.createElement('div'); assistantMessageDiv.classList.add('message', 'assistant-message'); assistantMessageDiv.innerHTML = '...'; // Indicateur visuel simple chatbox.appendChild(assistantMessageDiv); chatbox.scrollTop = chatbox.scrollHeight; console.log("Assistant placeholder added."); // LOG AJOUTÉ let currentResponse = ""; // Déclaration initiale let buffer = ''; // Initialisation buffer const decoder = new TextDecoder(); // Initialisation decoder try { console.log("Initiating fetch to /ask"); // LOG AJOUTÉ const response = await fetch('/ask', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'text/event-stream' }, body: JSON.stringify({ question: question }) }); console.log(`Fetch response received. Status: ${response.status}, OK: ${response.ok}`); // LOG AJOUTÉ if (!response.ok || !response.body) { // Essayer de lire le corps de l'erreur si possible let errorBody = "N/A"; try { errorBody = await response.text(); } catch (e) {} throw new Error(`Erreur serveur: ${response.status} ${response.statusText}. Body: ${errorBody}`); } const reader = response.body.getReader(); console.log("ReadableStream reader obtained. Starting read loop."); // LOG AJOUTÉ while (true) { console.log("Calling reader.read()..."); // LOG AJOUTÉ const { done, value } = await reader.read(); if (done) { console.log("Reader finished (done=true). Processing remaining buffer."); // LOG AJOUTÉ // Traiter le reste du buffer const result = processSSEBuffer(buffer, assistantMessageDiv, currentResponse); currentResponse = result.updatedResponse; console.log("Final response after stream ended:", currentResponse.substring(0,100)+"..."); // LOG AJOUTÉ break; // Sort de la boucle } // Decode et ajoute au buffer const chunk = decoder.decode(value, { stream: true }); console.log("Received chunk:", chunk); // LOG AJOUTÉ (peut être volumineux) buffer += chunk; // Traite le buffer et met à jour currentResponse/buffer console.log("Processing buffer with new chunk..."); // LOG AJOUTÉ const result = processSSEBuffer(buffer, assistantMessageDiv, currentResponse); currentResponse = result.updatedResponse; buffer = result.incomplete; console.log("Buffer remaining:", buffer); // LOG AJOUTÉ } } catch (error) { console.error('Erreur dans askQuestion (fetch ou stream):', error); // LOG AJOUTÉ // Affiche l'erreur dans la bulle de l'assistant if (assistantMessageDiv) { // Append error to existing content if any, otherwise set it assistantMessageDiv.innerHTML += `

حدث خطأ: ${error.message}`; chatbox.scrollTop = chatbox.scrollHeight; // Scroll pour voir l'erreur } else { // Fallback si assistantMessageDiv n'existe pas (ne devrait pas arriver ici) addMessage('assistant', `حدث خطأ: ${error.message}`); } } finally { console.log("Executing finally block: Enabling button."); // LOG AJOUTÉ sendButton.disabled = false; } } // --- Écouteurs d'événements (inchangés) --- sendButton.addEventListener('click', askQuestion); messageInput.addEventListener('keypress', function(e) { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); askQuestion(); } }); messageInput.addEventListener('input', adjustTextareaHeight); adjustTextareaHeight(); // Appel initial console.log("Chat script loaded and listeners attached."); // LOG AJOUTÉ