@@ -46,6 +46,8 @@ function App() {
46
46
messagesEndRef . current ?. scrollIntoView ( { behavior : "smooth" } ) ;
47
47
} ;
48
48
49
+ const [ isAssistantTyping , setIsAssistantTyping ] = useState < boolean > ( false ) ;
50
+
49
51
const createThreadAndRun = async ( ) : Promise < string | null > => {
50
52
if ( ! apiKey || ! assistantId ) return null ;
51
53
@@ -146,7 +148,7 @@ function App() {
146
148
const fetchMessages = async ( threadIdParam ?: string ) => {
147
149
const activeThreadId = threadIdParam || threadId ; // Use the passed threadId or fallback to state
148
150
if ( ! apiKey || ! activeThreadId ) return ;
149
-
151
+
150
152
try {
151
153
const response = await axios . get (
152
154
`https://api.openai.com/v1/threads/${ activeThreadId } /messages` ,
@@ -155,18 +157,21 @@ function App() {
155
157
"Content-Type" : "application/json" ,
156
158
"OpenAI-Beta" : "assistants=v2" ,
157
159
Authorization : `Bearer ${ apiKey } ` ,
158
- } ,
160
+ }
159
161
}
160
162
) ;
161
-
163
+
162
164
const filteredMessages = response . data . data . filter (
163
165
( message : { role : string } ) =>
164
166
message . role === "user" || message . role === "assistant"
165
167
) ;
166
-
168
+
167
169
setMessages ( filteredMessages . reverse ( ) ) ;
168
170
} catch ( error ) {
169
171
console . error ( "Erreur lors de la récupération des messages:" , error ) ;
172
+ } finally {
173
+ setIsLoading ( false ) ;
174
+ setIsAssistantTyping ( false ) ; // Hide typing indicator once message is received
170
175
}
171
176
} ;
172
177
@@ -184,10 +189,11 @@ function App() {
184
189
185
190
const runThreadAfterMessage = async ( ) => {
186
191
if ( ! apiKey || ! assistantId || ! threadId ) return ;
187
-
192
+
188
193
try {
189
194
setIsLoading ( true ) ; // Start loading
190
-
195
+ setIsAssistantTyping ( true ) ; // Display typing indicator
196
+
191
197
const response = await axios . post (
192
198
`https://api.openai.com/v1/threads/${ threadId } /runs` ,
193
199
{
@@ -198,10 +204,10 @@ function App() {
198
204
"Content-Type" : "application/json" ,
199
205
"OpenAI-Beta" : "assistants=v2" ,
200
206
Authorization : `Bearer ${ apiKey } ` ,
201
- } ,
207
+ }
202
208
}
203
209
) ;
204
-
210
+
205
211
const newRunId = response . data . id ; // Nouveau Run ID
206
212
setRunId ( newRunId ) ; // Mise à jour du Run ID
207
213
checkRunStatus ( newRunId ) ; // Vérifier le statut du run
@@ -242,7 +248,8 @@ function App() {
242
248
} catch ( error ) {
243
249
console . error ( "Erreur lors de l'envoi du message:" , error ) ;
244
250
} finally {
245
- setIsLoading ( false ) ; // Stop loading after the message has been sent
251
+ // Stop loading after the message has been sent
252
+ console . log ( "Message envoyé avec succès" ) ;
246
253
}
247
254
} ;
248
255
@@ -306,74 +313,99 @@ function App() {
306
313
elevation = { 0 }
307
314
square
308
315
>
309
- < List
316
+ < List >
317
+ { messages
318
+ . filter ( ( message , index , array ) => {
319
+ const firstUserMessageIndex = array . findIndex (
320
+ ( msg ) => msg . role === "user"
321
+ ) ;
322
+ return ! ( message . role === "user" && index === firstUserMessageIndex ) ;
323
+ } )
324
+ . map ( ( message ) => (
325
+ < ListItem
326
+ key = { message . id || Math . random ( ) }
327
+ sx = { {
328
+ display : "flex" ,
329
+ justifyContent :
330
+ message . role === "user" ? "flex-end" : "flex-start" ,
331
+ padding : "10px 0" ,
332
+ } }
333
+ >
334
+ < Box
335
+ sx = { {
336
+ display : "flex" ,
337
+ justifyContent :
338
+ message . role === "user" ? "flex-end" : "flex-start" ,
339
+ margin : 1 ,
340
+ } }
341
+ >
342
+ < ListItemText
343
+ primary = {
344
+ < Typography
345
+ variant = "body1"
346
+ component = "div"
347
+ sx = { {
348
+ backgroundColor :
349
+ message . role === "user" ? "#646cff" : "#333333" ,
350
+ padding : "8px 12px" ,
351
+ borderRadius : "12px" ,
352
+ maxWidth : "80%" ,
353
+ wordWrap : "break-word" ,
354
+ color : "#fff" ,
355
+ } }
356
+ >
357
+ < ReactMarkdown >
358
+ { formatMessageContent (
359
+ message . content ?. [ 0 ] ?. text ?. value || "Message indisponible"
360
+ ) }
361
+ </ ReactMarkdown >
362
+ </ Typography >
363
+ }
364
+ />
365
+ </ Box >
366
+ </ ListItem >
367
+ ) ) }
368
+
369
+ { /* Afficher le message temporaire pendant que l'assistant est en train de répondre */ }
370
+ { isAssistantTyping && (
371
+ < ListItem
372
+ sx = { {
373
+ display : "flex" ,
374
+ justifyContent : "flex-start" ,
375
+ padding : "10px 0" ,
376
+ } }
377
+ >
378
+ < Box
379
+ sx = { {
380
+ display : "flex" ,
381
+ justifyContent : "flex-start" ,
382
+ margin : 1 ,
383
+ } }
384
+ >
385
+ < ListItemText
386
+ primary = {
387
+ < Typography
388
+ variant = "body1"
389
+ component = "div"
310
390
sx = { {
311
- flex : 1 ,
312
- display : "flex" ,
313
- flexDirection : "column" ,
314
- gap : 1 ,
315
- margin : 5 ,
391
+ backgroundColor : "#333333" ,
392
+ padding : "8px 12px" ,
393
+ borderRadius : "12px" ,
394
+ maxWidth : "80%" ,
395
+ wordWrap : "break-word" ,
396
+ color : "#fff" ,
316
397
} }
317
398
>
318
- { /* Filtrer les messages pour exclure le premier message de l'utilisateur */ }
319
- { messages
320
- . filter ( ( message , index , array ) => {
321
- // Trouver le premier message de l'utilisateur
322
- const firstUserMessageIndex = array . findIndex (
323
- ( msg ) => msg . role === "user"
324
- ) ;
325
- // Exclure le premier message de l'utilisateur de l'affichage
326
- return ! (
327
- message . role === "user" && index === firstUserMessageIndex
328
- ) ;
329
- } )
330
- . map ( ( message ) => (
331
- < ListItem
332
- key = { message . id || Math . random ( ) }
333
- sx = { {
334
- display : "flex" ,
335
- justifyContent :
336
- message . role === "user" ? "flex-end" : "flex-start" ,
337
- padding : "10px 0" ,
338
- } }
339
- >
340
- < Box
341
- sx = { {
342
- display : "flex" ,
343
- justifyContent :
344
- message . role === "user" ? "flex-end" : "flex-start" ,
345
- margin : 1 ,
346
- } }
347
- >
348
- < ListItemText
349
- primary = {
350
- < Typography
351
- variant = "body1"
352
- component = "div"
353
- sx = { {
354
- backgroundColor :
355
- message . role === "user" ? "#646cff" : "#333333" ,
356
- padding : "8px 12px" ,
357
- borderRadius : "12px" ,
358
- maxWidth : "80%" ,
359
- wordWrap : "break-word" ,
360
- color : "#fff" ,
361
- } }
362
- >
363
- < ReactMarkdown >
364
- { formatMessageContent (
365
- message . content ?. [ 0 ] ?. text ?. value ||
366
- "Message indisponible"
367
- ) }
368
- </ ReactMarkdown >
369
- </ Typography >
370
- }
371
- />
372
- </ Box >
373
- </ ListItem >
374
- ) ) }
375
- < div ref = { messagesEndRef } />
376
- </ List >
399
+ L'assistant est en train de répondre...
400
+ </ Typography >
401
+ }
402
+ />
403
+ </ Box >
404
+ </ ListItem >
405
+ ) }
406
+ < div ref = { messagesEndRef } />
407
+ </ List >
408
+
377
409
</ Box >
378
410
< Divider />
379
411
{ isLoading ? (
0 commit comments