@@ -328,124 +328,27 @@ export default function ChatClient({ subdomain }: { subdomain: string }) {
328328 throw new Error ( 'Response body is missing' )
329329 }
330330
331- const messageIdMap = new Map < string , string > ( )
332-
333- // Get reader with proper cleanup
334- const reader = response . body . getReader ( )
335- const decoder = new TextDecoder ( )
336-
337- const processStream = async ( ) => {
338- let streamAborted = false
339-
340- // Add cleanup handler for abort
341- const cleanup = ( ) => {
342- streamAborted = true
343- try {
344- reader . releaseLock ( )
345- } catch ( error ) {
346- // Reader might already be released
347- logger . debug ( 'Reader already released:' , error )
348- }
349- setIsLoading ( false )
350- }
351-
352- // Listen for abort events
353- abortController . signal . addEventListener ( 'abort' , cleanup )
354-
355- try {
356- while ( ! streamAborted ) {
357- const { done, value } = await reader . read ( )
358-
359- if ( done ) {
360- setIsLoading ( false )
361- break
362- }
363-
364- if ( streamAborted ) {
365- break
366- }
367-
368- const chunk = decoder . decode ( value , { stream : true } )
369- const lines = chunk . split ( '\n\n' )
370-
371- for ( const line of lines ) {
372- if ( line . startsWith ( 'data: ' ) ) {
373- try {
374- const json = JSON . parse ( line . substring ( 6 ) )
375- const { blockId, chunk : contentChunk , event : eventType } = json
376-
377- if ( eventType === 'final' && json . data ) {
378- setIsLoading ( false )
379-
380- // Process final execution result for field extraction
381- const result = json . data
382- const nonStreamingLogs =
383- result . logs ?. filter ( ( log : any ) => ! messageIdMap . has ( log . blockId ) ) || [ ]
384-
385- // Chat field extraction will be handled by the backend using deployment outputConfigs
386-
387- return
388- }
389-
390- if ( blockId && contentChunk ) {
391- if ( ! messageIdMap . has ( blockId ) ) {
392- const newMessageId = crypto . randomUUID ( )
393- messageIdMap . set ( blockId , newMessageId )
394- setMessages ( ( prev ) => [
395- ...prev ,
396- {
397- id : newMessageId ,
398- content : contentChunk ,
399- type : 'assistant' ,
400- timestamp : new Date ( ) ,
401- isStreaming : true ,
402- } ,
403- ] )
404- } else {
405- const messageId = messageIdMap . get ( blockId )
406- if ( messageId ) {
407- setMessages ( ( prev ) =>
408- prev . map ( ( msg ) =>
409- msg . id === messageId
410- ? { ...msg , content : msg . content + contentChunk }
411- : msg
412- )
413- )
414- }
415- }
416- } else if ( blockId && eventType === 'end' ) {
417- const messageId = messageIdMap . get ( blockId )
418- if ( messageId ) {
419- setMessages ( ( prev ) =>
420- prev . map ( ( msg ) =>
421- msg . id === messageId ? { ...msg , isStreaming : false } : msg
422- )
423- )
424- }
425- }
426- } catch ( parseError ) {
427- logger . error ( 'Error parsing stream data:' , parseError )
428- // Continue processing other lines even if one fails
429- }
430- }
431- }
432- }
433- } catch ( streamError : unknown ) {
434- if ( streamError instanceof Error && streamError . name === 'AbortError' ) {
435- logger . info ( 'Stream processing aborted by user' )
436- return
437- }
438-
439- logger . error ( 'Error processing stream:' , streamError )
440- throw streamError
441- } finally {
442- // Ensure cleanup always happens
443- cleanup ( )
444- abortController . signal . removeEventListener ( 'abort' , cleanup )
331+ // Use the streaming hook with audio support
332+ const shouldPlayAudio = isVoiceInput || isVoiceFirstMode
333+ const audioHandler = shouldPlayAudio
334+ ? createAudioStreamHandler ( streamTextToAudio , DEFAULT_VOICE_SETTINGS . voiceId )
335+ : undefined
336+
337+ await handleStreamedResponse (
338+ response ,
339+ setMessages ,
340+ setIsLoading ,
341+ scrollToBottom ,
342+ userHasScrolled ,
343+ {
344+ voiceSettings : {
345+ isVoiceEnabled : shouldPlayAudio ,
346+ voiceId : DEFAULT_VOICE_SETTINGS . voiceId ,
347+ autoPlayResponses : shouldPlayAudio ,
348+ } ,
349+ audioStreamHandler : audioHandler ,
445350 }
446- }
447-
448- await processStream ( )
351+ )
449352 } catch ( error : any ) {
450353 // Clear timeout in case of error
451354 clearTimeout ( timeoutId )
0 commit comments