11'use client' ;
22
3- import { useState } from 'react' ;
3+ import { useState , useRef } from 'react' ;
44import { Message } from '@/types/chat' ;
55import { ModelConfig } from '@/hooks/use-model-config' ;
6+ import { useMetrics } from '@/hooks/use-metrics' ;
7+ import { useConversationCache } from '@/hooks/use-conversation-cache' ;
68
79export function useStream ( ) {
810 const [ messages , setMessages ] = useState < Message [ ] > ( [ ] ) ;
911 const [ isLoading , setIsLoading ] = useState ( false ) ;
12+ const abortController = useRef < AbortController | null > ( null ) ;
13+ const { metrics, updateMetrics, resetMetrics } = useMetrics ( ) ;
14+ const { saveMessages } = useConversationCache ( ) ;
15+
16+ const cancelGeneration = ( ) => {
17+ if ( abortController . current ) {
18+ abortController . current . abort ( ) ;
19+ abortController . current = null ;
20+ setIsLoading ( false ) ;
21+ }
22+ } ;
1023
1124 const streamMessage = async ( content : string , config : ModelConfig ) => {
1225 setIsLoading ( true ) ;
26+ resetMetrics ( ) ;
27+
1328 const userMessage : Message = {
1429 role : 'user' ,
1530 content,
@@ -19,6 +34,8 @@ export function useStream() {
1934 setMessages ( prev => [ ...prev , userMessage ] ) ;
2035
2136 try {
37+ abortController . current = new AbortController ( ) ;
38+
2239 const response = await fetch ( '/api/chat' , {
2340 method : 'POST' ,
2441 headers : {
@@ -28,6 +45,7 @@ export function useStream() {
2845 messages : [ ...messages , userMessage ] ,
2946 config,
3047 } ) ,
48+ signal : abortController . current . signal ,
3149 } ) ;
3250
3351 if ( ! response . ok ) throw new Error ( 'Failed to send message' ) ;
@@ -47,15 +65,31 @@ export function useStream() {
4765
4866 const text = new TextDecoder ( ) . decode ( value ) ;
4967 assistantMessage . content += text ;
68+ updateMetrics ( text ) ;
5069
5170 setMessages ( prev => [ ...prev . slice ( 0 , - 1 ) , { ...assistantMessage } ] ) ;
5271 }
72+
73+ // Save to IndexedDB after completion
74+ const updatedMessages = [ ...messages , userMessage , assistantMessage ] ;
75+ await saveMessages ( updatedMessages ) ;
5376 } catch ( error ) {
54- console . error ( 'Error streaming message:' , error ) ;
77+ if ( error instanceof Error && error . name === 'AbortError' ) {
78+ console . log ( 'Message generation cancelled' ) ;
79+ } else {
80+ console . error ( 'Error streaming message:' , error ) ;
81+ }
5582 } finally {
5683 setIsLoading ( false ) ;
84+ abortController . current = null ;
5785 }
5886 } ;
5987
60- return { messages, isLoading, streamMessage } ;
88+ return {
89+ messages,
90+ isLoading,
91+ streamMessage,
92+ cancelGeneration,
93+ metrics,
94+ } ;
6195}
0 commit comments