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

Update static/script.js

Browse files
Files changed (1) hide show
  1. static/script.js +44 -75
static/script.js CHANGED
@@ -24,120 +24,89 @@ function addMessage(role, text) {
24
 
25
  // Fonction pour envoyer la question via l'API SSE
26
  async function askQuestion() {
27
- const question = messageInput.value.trim();
28
- if (!question) return;
29
 
30
- addMessage('user', question);
31
- messageInput.value = ''; // Vide la zone de saisie
32
- sendButton.disabled = true; // Désactive le bouton pendant l'attente
33
- messageInput.style.height = 'auto'; // Réinitialise la hauteur (pour auto-ajustement si implémenté)
34
-
35
-
36
- // Crée un placeholder pour la réponse de l'assistant
37
- const assistantMessageDiv = document.createElement('div');
38
- assistantMessageDiv.classList.add('message', 'assistant-message');
39
- assistantMessageDiv.innerHTML = '<span class="thinking">...</span>'; // Indicateur visuel simple
40
- chatbox.appendChild(assistantMessageDiv);
41
- chatbox.scrollTop = chatbox.scrollHeight;
42
-
43
- let currentResponse = ""; // Pour accumuler la réponse streamée
44
 
45
  try {
46
- const response = await fetch('/ask', {
47
- method: 'POST',
48
- headers: {
49
- 'Content-Type': 'application/json',
50
- 'Accept': 'text/event-stream'
51
- },
52
- body: JSON.stringify({ question: question })
53
- });
54
-
55
- if (!response.ok || !response.body) {
56
- throw new Error(`Erreur serveur: ${response.status} ${response.statusText}`);
57
- }
58
-
59
- const reader = response.body.getReader();
60
- const decoder = new TextDecoder();
61
- let buffer = ''; // Buffer pour gérer les chunks SSE potentiellement fragmentés
62
 
63
  while (true) {
64
  const { done, value } = await reader.read();
65
  if (done) {
66
- console.log("Stream terminé par le serveur.");
67
- // Traiter le reste du buffer au cas où
68
- processSSEBuffer(buffer, assistantMessageDiv);
69
- break; // Sort de la boucle
 
70
  }
71
 
72
  buffer += decoder.decode(value, { stream: true });
73
- // Traite le buffer pour extraire les messages SSE complets
74
- buffer = processSSEBuffer(buffer, assistantMessageDiv);
 
 
75
 
76
- // Met à jour le contenu du div de l'assistant (déjà fait dans processSSEBuffer)
77
- chatbox.scrollTop = chatbox.scrollHeight; // Scroll pendant le stream
78
  }
79
 
80
  } catch (error) {
81
- console.error('Erreur lors de la requête ou du stream:', error);
82
- // Affiche l'erreur dans la bulle de l'assistant
83
- if (assistantMessageDiv) {
84
- assistantMessageDiv.innerHTML += `<br><br><strong style="color: #ffaaaa;">حدث خطأ: ${error.message}</strong>`;
85
- } else {
86
- addMessage('assistant', `<strong style="color: #ffaaaa;">حدث خطأ: ${error.message}</strong>`);
87
- }
88
  } finally {
89
- sendButton.disabled = false; // Réactive le bouton à la fin ou en cas d'erreur
90
- // Optionnel: redonner le focus à la zone de saisie
91
- // messageInput.focus();
92
  }
93
  }
94
 
95
  // Fonction pour traiter le buffer SSE et mettre à jour l'UI
96
- function processSSEBuffer(buffer, targetDiv) {
 
97
  let messages = buffer.split('\n\n');
98
- let incomplete = buffer.endsWith('\n\n') ? '' : messages.pop(); // Garde la partie incomplète pour le prochain chunk
 
 
99
 
100
  messages.forEach(message => {
101
- if (!message.trim()) return; // Ignore les messages vides
102
 
103
- let eventType = 'message'; // Type par défaut
104
  let dataLines = [];
105
 
106
  message.split('\n').forEach(line => {
107
  if (line.startsWith('event: ')) {
108
  eventType = line.substring(7).trim();
109
  } else if (line.startsWith('data: ')) {
110
- dataLines.push(line.substring(6)); // Ne pas .trim() ici pour préserver les espaces initiaux
111
  }
112
- // Ignorer les lignes 'id:' ou ':' (commentaires) pour l'instant
113
  });
114
 
115
- let data = dataLines.join('\n'); // Rejoint les lignes de données avec des sauts de ligne
116
-
117
- console.log(`SSE Event: ${eventType}, Data: ${data.substring(0, 50)}...`); // Log de débogage
118
 
119
  if (eventType === 'message') {
120
- // Si la réponse initiale est l'indicateur '...', la remplace
121
- if (targetDiv.querySelector('.thinking')) {
122
- targetDiv.innerHTML = ''; // Efface le "..."
123
- }
124
- // Ajoute les nouvelles données
125
- // Utiliser innerHTML avec précaution, idéalement nettoyer ou utiliser textContent si possible
126
- currentResponse += data;
127
- targetDiv.innerHTML = currentResponse.replace(/\n/g, '<br>'); // Met à jour avec la réponse accumulée
128
 
129
  } else if (eventType === 'end') {
130
- console.log("Fin de stream détectée par événement 'end'");
131
- sendButton.disabled = false; // Réactive explicitement le bouton
132
  } else if (eventType === 'error') {
133
- console.error("Erreur signalée par le serveur via SSE:", data);
134
- targetDiv.innerHTML += `<br><strong style="color: #ffaaaa;">خطأ من الخادم: ${data}</strong>`;
135
- sendButton.disabled = false;
 
136
  }
137
- // Gérer d'autres types d'événements si nécessaire
138
  });
139
- chatbox.scrollTop = chatbox.scrollHeight; // Scroll après traitement
140
- return incomplete; // Retourne la partie non traitée du buffer
 
 
 
 
 
141
  }
142
 
143
  // --- Auto-ajustement hauteur Textarea (Optionnel mais recommandé) ---
 
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();
79
  } else if (line.startsWith('data: ')) {
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é) ---