@@ -83,25 +83,23 @@ const loadConversationMessages = debounce(async (conversationId: string) => {
83
83
isLoadingMessages .value = true ;
84
84
try {
85
85
const res = await get (` /ai/chat/conversations/${conversationId }/messages ` );
86
- const messages = (res .data || []).map ((msg : ChatMessage ) => ( {
87
- role: msg . role as ChatMessageRole ,
88
- content: msg . content || ' ' ,
89
- timestamp: new Date (msg .created_ts || Date .now ()),
90
- conversationId: msg . conversation_id ,
91
- isStreaming: false ,
92
- })) ;
86
+ const messages = (res .data || []).map ((msg : any ) => {
87
+ const message : ChatMessage = {
88
+ ... msg ,
89
+ timestamp: new Date (msg .created_ts || Date .now ()),
90
+ };
91
+ return message ;
92
+ });
93
93
94
94
messages .sort (
95
- (a : ChatMessageType , b : ChatMessageType ) =>
96
- a .timestamp .getTime () - b .timestamp .getTime ()
95
+ (a : ChatMessage , b : ChatMessage ) =>
96
+ ( a .timestamp ? .getTime () || 0 ) - ( b .timestamp ? .getTime () || 0 )
97
97
);
98
98
99
99
chatHistory .splice (0 , chatHistory .length , ... messages );
100
100
currentConversationId .value = conversationId ;
101
101
} catch (error ) {
102
102
console .error (' Failed to load conversation messages:' , error );
103
- const errorMessage =
104
- error instanceof Error ? error .message : ' Failed to load messages' ;
105
103
} finally {
106
104
isLoadingMessages .value = false ;
107
105
// Scroll to bottom after loading messages
@@ -255,7 +253,7 @@ const resetChatbotConfig = () => {
255
253
};
256
254
257
255
// Initialize chat history
258
- const chatHistory = reactive <ChatMessageType []>([]);
256
+ const chatHistory = reactive <ChatMessage []>([]);
259
257
260
258
// Message handling
261
259
const sendMessage = async (message : string ) => {
@@ -268,16 +266,20 @@ const sendMessage = async (message: string) => {
268
266
role: ' user' ,
269
267
content: message ,
270
268
timestamp: new Date (),
269
+ conversation_id: currentConversationId .value || ' ' ,
270
+ status: ' completed' ,
271
271
});
272
272
// Scroll to bottom after adding user message
273
273
messageListRef .value ?.scrollToBottom ();
274
274
275
275
const responseIndex = chatHistory .length ;
276
276
chatHistory .push ({
277
- role: ' system' ,
278
- content: ' ' ,
277
+ role: ' assistant' ,
279
278
timestamp: new Date (),
280
279
isStreaming: true ,
280
+ conversation_id: currentConversationId .value || ' ' ,
281
+ status: ' pending' ,
282
+ contentsMap: {},
281
283
});
282
284
// Scroll to bottom after adding system message placeholder
283
285
messageListRef .value ?.scrollToBottom ();
@@ -377,15 +379,16 @@ const sendStreamingRequest = async (
377
379
const reader = response .body ! .getReader ();
378
380
const decoder = new TextDecoder ();
379
381
let buffer = ' ' ;
380
- let fullResponse = ' ' ;
381
382
382
383
const processStream = async () => {
383
384
try {
384
385
const { value, done } = await reader .read ();
385
386
387
+ const currentMessage = chatHistory [responseIndex ];
388
+
386
389
if (done ) {
387
- if (chatHistory [ responseIndex ] ) {
388
- chatHistory [ responseIndex ] .isStreaming = false ;
390
+ if (currentMessage ) {
391
+ currentMessage .isStreaming = false ;
389
392
// Scroll to bottom when streaming is complete
390
393
messageListRef .value ?.scrollToBottom ();
391
394
}
@@ -400,36 +403,67 @@ const sendStreamingRequest = async (
400
403
for (const line of lines ) {
401
404
if (line .startsWith (' data:' )) {
402
405
try {
406
+ // Event data
403
407
const eventData = line .slice (5 ).trim ();
408
+
409
+ // Skip if empty
404
410
if (eventData === ' ' ) continue ;
405
411
412
+ // Parse stream message
406
413
const chunk: ChatbotStreamMessage = JSON .parse (eventData );
407
414
415
+ // Initial update with conversation id
408
416
if (chunk .is_initial ) {
409
417
currentConversationId .value = chunk .conversation_id ! ;
410
418
continue ;
411
419
}
412
420
421
+ // Update conversation title
413
422
if (chunk .conversation_title ) {
414
423
if (! currentConversation .value ) {
415
- currentConversation .value = {
416
- title: chunk .conversation_title ,
417
- };
418
- } else {
419
- currentConversation .value .title =
420
- chunk .conversation_title ;
424
+ currentConversation .value = {};
421
425
}
426
+ currentConversation .value .title = chunk .conversation_title ;
422
427
}
423
428
424
- fullResponse += chunk .content || ' ' ;
425
- if (chatHistory [responseIndex ]) {
426
- chatHistory [responseIndex ].content = fullResponse ;
427
- chatHistory [responseIndex ].conversationId =
428
- chunk .conversation_id ;
429
- // Scroll to bottom during streaming
430
- messageListRef .value ?.scrollToBottom ();
429
+ // Get chunk content
430
+ const contentKey = chunk .key || ' ' ;
431
+ if (! currentMessage .contents ?.length ) {
432
+ currentMessage .contents = [];
433
+ }
434
+ const contentIndex = currentMessage .contents .findIndex (
435
+ c => c .key === contentKey
436
+ );
437
+ if (contentIndex >= 0 ) {
438
+ // Update existing content
439
+ const content = currentMessage .contents [contentIndex ];
440
+ if (chunk .type === ' text' ) {
441
+ content .content += chunk .content || ' ' ;
442
+ if (chunk .is_text_done ) {
443
+ content .isStreaming = false ;
444
+ }
445
+ } else if (chunk .type === ' action' ) {
446
+ currentMessage .contents [contentIndex ] = {
447
+ ... content ,
448
+ ... chunk ,
449
+ };
450
+ }
451
+ } else {
452
+ // Add new content
453
+ if (chunk .type === ' text' ) {
454
+ const newContent: ChatMessageContent = {
455
+ ... chunk ,
456
+ isStreaming: true ,
457
+ };
458
+ currentMessage .contents .push (newContent );
459
+ } else if (chunk .type === ' action' ) {
460
+ currentMessage .contents .push ({
461
+ ... chunk ,
462
+ });
463
+ }
431
464
}
432
465
466
+ // Final response
433
467
if (chunk .is_done ) {
434
468
if (chatHistory [responseIndex ]) {
435
469
chatHistory [responseIndex ].isStreaming = false ;
0 commit comments