AxL95 commited on
Commit
cd06911
·
verified ·
1 Parent(s): 2017062

Update frontend/src/components/ChatInterface.jsx

Browse files
frontend/src/components/ChatInterface.jsx CHANGED
@@ -34,11 +34,13 @@ const ChatInterface = ({
34
  useEffect(() => {
35
  scrollToBottom();
36
 
 
37
  if (updateIntervalRef.current) {
38
  clearInterval(updateIntervalRef.current);
39
  updateIntervalRef.current = null;
40
  }
41
 
 
42
  if (isStreaming && currentStreamId) {
43
  updateIntervalRef.current = setInterval(() => {
44
  if (accumulatedText.current.length > 0) {
@@ -51,9 +53,10 @@ const ChatInterface = ({
51
  });
52
  accumulatedText.current = '';
53
  }
54
- }, 100);
55
  }
56
 
 
57
  return () => {
58
  if (updateIntervalRef.current) {
59
  clearInterval(updateIntervalRef.current);
@@ -66,24 +69,31 @@ const ChatInterface = ({
66
  setIsLoading(true);
67
  const userMessageId = `user-${Date.now()}`;
68
 
 
69
  setMessages(prev => [...prev, {
70
  sender: 'user',
71
  text: message,
72
  id: userMessageId
73
  }]);
 
74
  const updatedConversationId = await onMessageSent(message);
75
 
 
76
  const streamMessageId = `bot-${Date.now()}`;
77
  setCurrentStreamId(streamMessageId);
78
 
 
79
  setMessages(prev => {
 
80
  const userMessageExists = prev.some(m => m.id === userMessageId);
81
 
 
82
  const updatedMessages = userMessageExists ? prev : [
83
  ...prev,
84
  { sender: 'user', text: message, id: userMessageId }
85
  ];
86
 
 
87
  return [...updatedMessages, {
88
  sender: 'bot',
89
  text: '',
@@ -91,10 +101,11 @@ const ChatInterface = ({
91
  }];
92
  });
93
 
94
- setIsLoading(false);
95
- setIsStreaming(true);
96
 
97
- const response = await fetch('/api/chat', {
 
98
  method: 'POST',
99
  headers: { 'Content-Type': 'application/json' },
100
  credentials: 'include',
@@ -105,6 +116,7 @@ const ChatInterface = ({
105
  }),
106
  });
107
 
 
108
  if (!response.ok) {
109
  const errorData = await response.json();
110
 
@@ -124,6 +136,7 @@ const ChatInterface = ({
124
  throw new Error(`Chat API error ${response.status}`);
125
  }
126
 
 
127
  if (response.headers.get('content-type')?.includes('text/event-stream') && response.body) {
128
  const reader = response.body.getReader();
129
  const decoder = new TextDecoder();
@@ -133,6 +146,7 @@ const ChatInterface = ({
133
  const { done, value } = await reader.read();
134
  if (done) break;
135
 
 
136
  const chunk = decoder.decode(value);
137
  const lines = chunk.split('\n\n');
138
 
@@ -152,6 +166,7 @@ const ChatInterface = ({
152
  setCurrentStreamId(null);
153
  setIsLoading(false);
154
 
 
155
  setMessages(prev =>
156
  prev.map(msg =>
157
  msg.id === streamMessageId
@@ -160,33 +175,53 @@ const ChatInterface = ({
160
  )
161
  );
162
 
 
163
  if (typeof refreshConversationList === 'function') {
164
  setTimeout(refreshConversationList, 100);
165
  }
166
 
167
- return;
168
  }
169
- if (data.content) {
170
- fullText += data.content;
 
 
 
 
 
 
 
 
171
 
172
- // Update immediately without accumulation
173
- setMessages(prev => {
174
- return prev.map(msg =>
175
- msg.id === streamMessageId
176
- ? { ...msg, text: fullText }
177
- : msg
178
- );
179
- });
180
 
181
- // Ensure scroll
182
- requestAnimationFrame(scrollToBottom);
183
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
184
  else if (data.type === 'error') {
185
  console.error("SSE Error received:", data.error);
186
  setIsStreaming(false);
187
  setCurrentStreamId(null);
188
  setIsLoading(false);
189
 
 
190
  setMessages(prev =>
191
  prev.map(msg =>
192
  msg.id === streamMessageId
@@ -203,6 +238,7 @@ const ChatInterface = ({
203
  }
204
  }
205
  else {
 
206
  console.log("Received non-streaming response.");
207
  const responseData = await response.json();
208
  setIsStreaming(false);
@@ -217,6 +253,7 @@ const ChatInterface = ({
217
  )
218
  );
219
 
 
220
  if (typeof refreshConversationList === 'function') {
221
  setTimeout(refreshConversationList, 100);
222
  }
@@ -228,6 +265,7 @@ const ChatInterface = ({
228
  setCurrentStreamId(null);
229
  setIsLoading(false);
230
 
 
231
  setMessages(prev => {
232
  const filteredMessages = prev.filter(m => m.id !== currentStreamId);
233
  return [...filteredMessages,
@@ -259,9 +297,11 @@ const ChatInterface = ({
259
  };
260
 
261
  const isMarkdown = (text, sender) => {
 
262
  if (sender === 'bot') {
263
  return true;
264
  }
 
265
  return /(?:\*\*|__|##|\*|_|`|>|\d+\.\s|\-\s|\[.*\]\(.*\))/.test(text);
266
  };
267
 
 
34
  useEffect(() => {
35
  scrollToBottom();
36
 
37
+ // Nettoyer l'intervalle précédent si existant
38
  if (updateIntervalRef.current) {
39
  clearInterval(updateIntervalRef.current);
40
  updateIntervalRef.current = null;
41
  }
42
 
43
+ // Créer un nouvel intervalle si en streaming
44
  if (isStreaming && currentStreamId) {
45
  updateIntervalRef.current = setInterval(() => {
46
  if (accumulatedText.current.length > 0) {
 
53
  });
54
  accumulatedText.current = '';
55
  }
56
+ }, 100); // Mise à jour toutes les 100ms pour plus de fluidité
57
  }
58
 
59
+ // Nettoyage lors du démontage
60
  return () => {
61
  if (updateIntervalRef.current) {
62
  clearInterval(updateIntervalRef.current);
 
69
  setIsLoading(true);
70
  const userMessageId = `user-${Date.now()}`;
71
 
72
+ // Ajouter le message de l'utilisateur
73
  setMessages(prev => [...prev, {
74
  sender: 'user',
75
  text: message,
76
  id: userMessageId
77
  }]);
78
+ // Envoyer le message au backend
79
  const updatedConversationId = await onMessageSent(message);
80
 
81
+ // Créer un ID unique pour le message en streaming
82
  const streamMessageId = `bot-${Date.now()}`;
83
  setCurrentStreamId(streamMessageId);
84
 
85
+ // Ajouter un message bot vide pour le streaming
86
  setMessages(prev => {
87
+ // Vérifier si le message utilisateur existe déjà
88
  const userMessageExists = prev.some(m => m.id === userMessageId);
89
 
90
+ // Si pour une raison quelconque le message utilisateur a disparu, le rajouter
91
  const updatedMessages = userMessageExists ? prev : [
92
  ...prev,
93
  { sender: 'user', text: message, id: userMessageId }
94
  ];
95
 
96
+ // Ajouter le message bot de streaming
97
  return [...updatedMessages, {
98
  sender: 'bot',
99
  text: '',
 
101
  }];
102
  });
103
 
104
+ setIsLoading(false); // Plus de chargement mais streaming
105
+ setIsStreaming(true); // Commencer le streaming
106
 
107
+ // Faire la requête au backend
108
+ const response = await fetch('http://localhost:8000/api/chat', {
109
  method: 'POST',
110
  headers: { 'Content-Type': 'application/json' },
111
  credentials: 'include',
 
116
  }),
117
  });
118
 
119
+ // Gestion des erreurs HTTP
120
  if (!response.ok) {
121
  const errorData = await response.json();
122
 
 
136
  throw new Error(`Chat API error ${response.status}`);
137
  }
138
 
139
+ // Traiter la réponse en streaming si disponible
140
  if (response.headers.get('content-type')?.includes('text/event-stream') && response.body) {
141
  const reader = response.body.getReader();
142
  const decoder = new TextDecoder();
 
146
  const { done, value } = await reader.read();
147
  if (done) break;
148
 
149
+ // Décoder et traiter les données
150
  const chunk = decoder.decode(value);
151
  const lines = chunk.split('\n\n');
152
 
 
166
  setCurrentStreamId(null);
167
  setIsLoading(false);
168
 
169
+ // Mise à jour finale
170
  setMessages(prev =>
171
  prev.map(msg =>
172
  msg.id === streamMessageId
 
175
  )
176
  );
177
 
178
+ // Rafraîchir la liste des conversations
179
  if (typeof refreshConversationList === 'function') {
180
  setTimeout(refreshConversationList, 100);
181
  }
182
 
183
+ return; // Sortir de la boucle une fois terminé
184
  }
185
+ else if (data.content) {
186
+ // Ajouter le contenu du chunk
187
+ fullText += data.content;
188
+ accumulatedText.current += data.content;
189
+
190
+ // Mise à jour moins fréquente de l'interface
191
+ if (accumulatedText.current.length >= updateThreshold || data.content.includes('\n')) {
192
+ setMessages(prev => {
193
+ const userMsg = prev.find(m => m.sender === 'user' && m.text === message);
194
+ const botMsg = prev.find(m => m.id === streamMessageId);
195
 
196
+ const updatedMessages = userMsg ? prev : [
197
+ ...prev,
198
+ { sender: 'user', text: message, id: `user-${Date.now()}` }
199
+ ];
 
 
 
 
200
 
201
+ if (botMsg) {
202
+ return updatedMessages.map(msg =>
203
+ msg.id === streamMessageId ? { ...msg, text: fullText } : msg
204
+ );
205
+ } else {
206
+ return [...updatedMessages, { sender: 'bot', text: fullText, id: streamMessageId }];
207
+ }
208
+ });
209
+
210
+ accumulatedText.current = ''; // Réinitialiser l'accumulateur
211
+
212
+ // Faire défiler vers le bas
213
+ requestAnimationFrame(() => {
214
+ scrollToBottom();
215
+ });
216
+ }
217
+ }
218
  else if (data.type === 'error') {
219
  console.error("SSE Error received:", data.error);
220
  setIsStreaming(false);
221
  setCurrentStreamId(null);
222
  setIsLoading(false);
223
 
224
+ // Remplacer par un message d'erreur
225
  setMessages(prev =>
226
  prev.map(msg =>
227
  msg.id === streamMessageId
 
238
  }
239
  }
240
  else {
241
+ // Fallback pour les réponses non-streaming
242
  console.log("Received non-streaming response.");
243
  const responseData = await response.json();
244
  setIsStreaming(false);
 
253
  )
254
  );
255
 
256
+ // Rafraîchir la liste des conversations
257
  if (typeof refreshConversationList === 'function') {
258
  setTimeout(refreshConversationList, 100);
259
  }
 
265
  setCurrentStreamId(null);
266
  setIsLoading(false);
267
 
268
+ // Afficher l'erreur
269
  setMessages(prev => {
270
  const filteredMessages = prev.filter(m => m.id !== currentStreamId);
271
  return [...filteredMessages,
 
297
  };
298
 
299
  const isMarkdown = (text, sender) => {
300
+ // Forcer le rendu Markdown pour TOUS les messages du bot
301
  if (sender === 'bot') {
302
  return true;
303
  }
304
+ // Pour les messages utilisateur, vérifier la présence de syntaxe Markdown
305
  return /(?:\*\*|__|##|\*|_|`|>|\d+\.\s|\-\s|\[.*\]\(.*\))/.test(text);
306
  };
307