Trabis commited on
Commit
a665b4f
·
verified ·
1 Parent(s): c61873b

Update static/script.js

Browse files
Files changed (1) hide show
  1. static/script.js +118 -79
static/script.js CHANGED
@@ -1,78 +1,27 @@
1
  const chatbox = document.getElementById('chatbox');
2
- const messageInput = document.getElementById('message-input'); // Renommé pour clarté
3
  const sendButton = document.getElementById('send-button');
4
 
5
- // Fonction pour ajouter un message au chatbox
6
  function addMessage(role, text) {
7
  const messageDiv = document.createElement('div');
8
  messageDiv.classList.add('message', role === 'user' ? 'user-message' : 'assistant-message');
9
-
10
- // IMPORTANT: Pour afficher le texte brut et éviter les injections XSS
11
- // Utilisez textContent au lieu de innerHTML si vous n'avez pas besoin d'interpréter le HTML reçu
12
- // messageDiv.textContent = text;
13
-
14
- // SI vous avez besoin d'interpréter le HTML (ex: <br> pour les sauts de ligne, ou si le LLM génère du HTML/Markdown simple)
15
- // Soyez prudent avec le contenu généré par le LLM si vous utilisez innerHTML.
16
- // Une bibliothèque de Markdown comme 'marked.js' serait plus sûre pour rendre le Markdown.
17
- // Pour une simple substitution de saut de ligne:
18
  messageDiv.innerHTML = text.replace(/\n/g, '<br>');
19
-
20
  chatbox.appendChild(messageDiv);
21
- // Scroll vers le bas pour voir le nouveau message
22
  chatbox.scrollTop = chatbox.scrollHeight;
23
  }
24
 
25
- // Fonction pour envoyer la question via l'API SSE
26
- async function askQuestion() {
27
- // ... (début de la fonction inchangé) ...
28
-
29
- let currentResponse = ""; // Déclaration initiale ICI
30
-
31
- try {
32
- // ... (fetch et initialisation reader/decoder) ...
33
- let buffer = '';
34
-
35
- while (true) {
36
- const { done, value } = await reader.read();
37
- if (done) {
38
- console.log("Stream terminé par le serveur.");
39
- // Traiter le reste du buffer
40
- const result = processSSEBuffer(buffer, assistantMessageDiv, currentResponse); // Passe currentResponse
41
- currentResponse = result.updatedResponse; // Met à jour currentResponse
42
- break;
43
- }
44
-
45
- buffer += decoder.decode(value, { stream: true });
46
- // Traite le buffer et met à jour currentResponse
47
- const result = processSSEBuffer(buffer, assistantMessageDiv, currentResponse); // Passe currentResponse
48
- currentResponse = result.updatedResponse; // Met à jour currentResponse
49
- buffer = result.incomplete; // Met à jour le buffer
50
-
51
- // Scroll (déjà fait dans processSSEBuffer)
52
- // chatbox.scrollTop = chatbox.scrollHeight;
53
- }
54
-
55
- } catch (error) {
56
- // ... (gestion d'erreur inchangée) ...
57
- } finally {
58
- sendButton.disabled = false;
59
- }
60
- }
61
-
62
- // Fonction pour traiter le buffer SSE et mettre à jour l'UI
63
- // Accepte la réponse actuelle et le div cible, retourne la nouvelle réponse accumulée
64
  function processSSEBuffer(buffer, targetDiv, currentResponseAccumulated) {
 
65
  let messages = buffer.split('\n\n');
66
  let incomplete = buffer.endsWith('\n\n') ? '' : messages.pop();
67
-
68
- let newResponsePart = ''; // Pour accumuler les NOUVELLES données de ce buffer
69
 
70
  messages.forEach(message => {
71
  if (!message.trim()) return;
72
-
73
  let eventType = 'message';
74
  let dataLines = [];
75
-
76
  message.split('\n').forEach(line => {
77
  if (line.startsWith('event: ')) {
78
  eventType = line.substring(7).trim();
@@ -80,54 +29,144 @@ function processSSEBuffer(buffer, targetDiv, currentResponseAccumulated) {
80
  dataLines.push(line.substring(6));
81
  }
82
  });
83
-
84
  let data = dataLines.join('\n');
85
- console.log(`SSE Event: ${eventType}, Data: ${data.substring(0, 50)}...`); // Log
86
 
87
  if (eventType === 'message') {
88
  if (targetDiv.querySelector('.thinking')) {
89
- targetDiv.innerHTML = ''; // Efface le "..."
 
90
  }
91
- newResponsePart += data; // Accumule seulement la nouvelle partie
92
-
93
  } else if (eventType === 'end') {
94
- console.log("Fin de stream détectée par événement 'end'");
95
  sendButton.disabled = false;
96
  } else if (eventType === 'error') {
97
- console.error("Erreur signalée par le serveur via SSE:", data);
98
- // Ajoute l'erreur à la fin de la réponse actuelle
99
  currentResponseAccumulated += `<br><strong style="color: #ffaaaa;">خطأ من الخادم: ${data}</strong>`;
100
  sendButton.disabled = false;
101
  }
102
  });
103
 
104
- // Met à jour l'UI avec la réponse complète (ancienne + nouvelle)
105
  const updatedResponse = currentResponseAccumulated + newResponsePart;
 
106
  targetDiv.innerHTML = updatedResponse.replace(/\n/g, '<br>');
107
-
108
  chatbox.scrollTop = chatbox.scrollHeight;
109
- return { incomplete: incomplete, updatedResponse: updatedResponse }; // Retourne la partie non traitée et la réponse mise à jour
110
- }
111
 
112
- // --- Auto-ajustement hauteur Textarea (Optionnel mais recommandé) ---
113
- function adjustTextareaHeight() {
114
- messageInput.style.height = 'auto'; // Réinitialise pour obtenir scrollHeight correct
115
- messageInput.style.height = (messageInput.scrollHeight) + 'px'; // Ajuste à la hauteur du contenu
116
  }
117
 
118
- messageInput.addEventListener('input', adjustTextareaHeight);
 
119
 
120
 
121
- // --- Écouteurs d'événements ---
122
- sendButton.addEventListener('click', askQuestion);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
 
 
 
124
  messageInput.addEventListener('keypress', function(e) {
125
- // Envoi avec Entrée (sauf si Shift est pressé pour un saut de ligne)
126
  if (e.key === 'Enter' && !e.shiftKey) {
127
- e.preventDefault(); // Empêche le saut de ligne dans le textarea
128
  askQuestion();
129
  }
130
  });
 
 
131
 
132
- // Ajuste la hauteur initiale au cas il y aurait du texte pré-rempli (peu probable ici)
133
- adjustTextareaHeight();
 
1
  const chatbox = document.getElementById('chatbox');
2
+ const messageInput = document.getElementById('message-input');
3
  const sendButton = document.getElementById('send-button');
4
 
5
+ // --- addMessage function (inchangée) ---
6
  function addMessage(role, text) {
7
  const messageDiv = document.createElement('div');
8
  messageDiv.classList.add('message', role === 'user' ? 'user-message' : 'assistant-message');
 
 
 
 
 
 
 
 
 
9
  messageDiv.innerHTML = text.replace(/\n/g, '<br>');
 
10
  chatbox.appendChild(messageDiv);
 
11
  chatbox.scrollTop = chatbox.scrollHeight;
12
  }
13
 
14
+ // --- processSSEBuffer function (inchangée - version Méthode 1) ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  function processSSEBuffer(buffer, targetDiv, currentResponseAccumulated) {
16
+ console.log("Processing buffer:", buffer); // LOG AJOUTÉ
17
  let messages = buffer.split('\n\n');
18
  let incomplete = buffer.endsWith('\n\n') ? '' : messages.pop();
19
+ let newResponsePart = '';
 
20
 
21
  messages.forEach(message => {
22
  if (!message.trim()) return;
 
23
  let eventType = 'message';
24
  let dataLines = [];
 
25
  message.split('\n').forEach(line => {
26
  if (line.startsWith('event: ')) {
27
  eventType = line.substring(7).trim();
 
29
  dataLines.push(line.substring(6));
30
  }
31
  });
 
32
  let data = dataLines.join('\n');
33
+ console.log(`--> SSE Event Parsed: ${eventType}, Data: ${data.substring(0, 100)}...`); // LOG AJOUTÉ
34
 
35
  if (eventType === 'message') {
36
  if (targetDiv.querySelector('.thinking')) {
37
+ console.log("Replacing 'thinking' indicator"); // LOG AJOUTÉ
38
+ targetDiv.innerHTML = '';
39
  }
40
+ newResponsePart += data;
 
41
  } else if (eventType === 'end') {
42
+ console.log("Fin de stream détectée (event: end)"); // LOG AJOUTÉ
43
  sendButton.disabled = false;
44
  } else if (eventType === 'error') {
45
+ console.error("Erreur SSE du serveur:", data); // LOG AJOUTÉ
 
46
  currentResponseAccumulated += `<br><strong style="color: #ffaaaa;">خطأ من الخادم: ${data}</strong>`;
47
  sendButton.disabled = false;
48
  }
49
  });
50
 
 
51
  const updatedResponse = currentResponseAccumulated + newResponsePart;
52
+ // Limiter la fréquence de mise à jour de innerHTML si beaucoup de petits chunks
53
  targetDiv.innerHTML = updatedResponse.replace(/\n/g, '<br>');
 
54
  chatbox.scrollTop = chatbox.scrollHeight;
55
+ // console.log("Updated Response:", updatedResponse.substring(0, 100) + "..."); // Optionnel: peut être très verbeux
 
56
 
57
+ return { incomplete: incomplete, updatedResponse: updatedResponse };
 
 
 
58
  }
59
 
60
+ // --- adjustTextareaHeight function (inchangée) ---
61
+ function adjustTextareaHeight() { /* ... */ }
62
 
63
 
64
+ // --- askQuestion function (avec plus de logs) ---
65
+ async function askQuestion() {
66
+ console.log("askQuestion called"); // LOG AJOUTÉ
67
+ const question = messageInput.value.trim();
68
+ if (!question) {
69
+ console.log("Question is empty, aborting."); // LOG AJOUTÉ
70
+ return;
71
+ }
72
+
73
+ addMessage('user', question);
74
+ messageInput.value = '';
75
+ sendButton.disabled = true;
76
+ adjustTextareaHeight(); // Réajuste après vidage
77
+ console.log("User message added, button disabled."); // LOG AJOUTÉ
78
+
79
+ // Crée un placeholder pour la réponse de l'assistant
80
+ const assistantMessageDiv = document.createElement('div');
81
+ assistantMessageDiv.classList.add('message', 'assistant-message');
82
+ assistantMessageDiv.innerHTML = '<span class="thinking">...</span>'; // Indicateur visuel simple
83
+ chatbox.appendChild(assistantMessageDiv);
84
+ chatbox.scrollTop = chatbox.scrollHeight;
85
+ console.log("Assistant placeholder added."); // LOG AJOUTÉ
86
+
87
+ let currentResponse = ""; // Déclaration initiale
88
+ let buffer = ''; // Initialisation buffer
89
+ const decoder = new TextDecoder(); // Initialisation decoder
90
+
91
+ try {
92
+ console.log("Initiating fetch to /ask"); // LOG AJOUTÉ
93
+ const response = await fetch('/ask', {
94
+ method: 'POST',
95
+ headers: {
96
+ 'Content-Type': 'application/json',
97
+ 'Accept': 'text/event-stream'
98
+ },
99
+ body: JSON.stringify({ question: question })
100
+ });
101
+
102
+ console.log(`Fetch response received. Status: ${response.status}, OK: ${response.ok}`); // LOG AJOUTÉ
103
+
104
+ if (!response.ok || !response.body) {
105
+ // Essayer de lire le corps de l'erreur si possible
106
+ let errorBody = "N/A";
107
+ try {
108
+ errorBody = await response.text();
109
+ } catch (e) {}
110
+ throw new Error(`Erreur serveur: ${response.status} ${response.statusText}. Body: ${errorBody}`);
111
+ }
112
+
113
+ const reader = response.body.getReader();
114
+ console.log("ReadableStream reader obtained. Starting read loop."); // LOG AJOUTÉ
115
+
116
+ while (true) {
117
+ console.log("Calling reader.read()..."); // LOG AJOUTÉ
118
+ const { done, value } = await reader.read();
119
+
120
+ if (done) {
121
+ console.log("Reader finished (done=true). Processing remaining buffer."); // LOG AJOUTÉ
122
+ // Traiter le reste du buffer
123
+ const result = processSSEBuffer(buffer, assistantMessageDiv, currentResponse);
124
+ currentResponse = result.updatedResponse;
125
+ console.log("Final response after stream ended:", currentResponse.substring(0,100)+"..."); // LOG AJOUTÉ
126
+ break; // Sort de la boucle
127
+ }
128
+
129
+ // Decode et ajoute au buffer
130
+ const chunk = decoder.decode(value, { stream: true });
131
+ console.log("Received chunk:", chunk); // LOG AJOUTÉ (peut être volumineux)
132
+ buffer += chunk;
133
+
134
+ // Traite le buffer et met à jour currentResponse/buffer
135
+ console.log("Processing buffer with new chunk..."); // LOG AJOUTÉ
136
+ const result = processSSEBuffer(buffer, assistantMessageDiv, currentResponse);
137
+ currentResponse = result.updatedResponse;
138
+ buffer = result.incomplete;
139
+ console.log("Buffer remaining:", buffer); // LOG AJOUTÉ
140
+
141
+ }
142
+
143
+ } catch (error) {
144
+ console.error('Erreur dans askQuestion (fetch ou stream):', error); // LOG AJOUTÉ
145
+ // Affiche l'erreur dans la bulle de l'assistant
146
+ if (assistantMessageDiv) {
147
+ // Append error to existing content if any, otherwise set it
148
+ assistantMessageDiv.innerHTML += `<br><br><strong style="color: #ffaaaa;">حدث خطأ: ${error.message}</strong>`;
149
+ chatbox.scrollTop = chatbox.scrollHeight; // Scroll pour voir l'erreur
150
+ } else {
151
+ // Fallback si assistantMessageDiv n'existe pas (ne devrait pas arriver ici)
152
+ addMessage('assistant', `<strong style="color: #ffaaaa;">حدث خطأ: ${error.message}</strong>`);
153
+ }
154
+ } finally {
155
+ console.log("Executing finally block: Enabling button."); // LOG AJOUTÉ
156
+ sendButton.disabled = false;
157
+ }
158
+ }
159
+
160
 
161
+ // --- Écouteurs d'événements (inchangés) ---
162
+ sendButton.addEventListener('click', askQuestion);
163
  messageInput.addEventListener('keypress', function(e) {
 
164
  if (e.key === 'Enter' && !e.shiftKey) {
165
+ e.preventDefault();
166
  askQuestion();
167
  }
168
  });
169
+ messageInput.addEventListener('input', adjustTextareaHeight);
170
+ adjustTextareaHeight(); // Appel initial
171
 
172
+ console.log("Chat script loaded and listeners attached."); // LOG AJOUTÉ