From 3c68cbc955573467e4fb95cfd5db1f3d96a9e88f Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Wed, 7 Feb 2024 04:42:39 +0530 Subject: [PATCH] fix(stream err on changing conversation) --- frontend/src/Navigation.tsx | 1 - frontend/src/conversation/Conversation.tsx | 23 ++++++++++++++----- frontend/src/conversation/conversationApi.ts | 4 ++++ .../src/conversation/conversationSlice.ts | 8 ++++++- frontend/src/hooks/index.ts | 19 +++++++-------- 5 files changed, 36 insertions(+), 19 deletions(-) diff --git a/frontend/src/Navigation.tsx b/frontend/src/Navigation.tsx index c85b87b..c3bf0a9 100644 --- a/frontend/src/Navigation.tsx +++ b/frontend/src/Navigation.tsx @@ -97,7 +97,6 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) { fetchConversations(); } }, [conversations, dispatch]); - async function fetchConversations() { return await getConversations() .then((fetchedConversations) => { diff --git a/frontend/src/conversation/Conversation.tsx b/frontend/src/conversation/Conversation.tsx index b541c87..6163fcd 100644 --- a/frontend/src/conversation/Conversation.tsx +++ b/frontend/src/conversation/Conversation.tsx @@ -4,7 +4,7 @@ import { useDarkTheme } from '../hooks'; import Hero from '../Hero'; import { AppDispatch } from '../store'; import ConversationBubble from './ConversationBubble'; -import { +import conversationSlice, { addQuery, fetchAnswer, selectQueries, @@ -17,16 +17,17 @@ import Spinner from './../assets/spinner.svg'; import { FEEDBACK, Query } from './conversationModels'; import { sendFeedback } from './conversationApi'; import ArrowDown from './../assets/arrow-down.svg'; - +import { selectConversationId } from '../preferences/preferenceSlice'; export default function Conversation() { const queries = useSelector(selectQueries); const status = useSelector(selectStatus); + const conversationId = useSelector(selectConversationId) const dispatch = useDispatch(); const endMessageRef = useRef(null); const inputRef = useRef(null); const [isDarkTheme]= useDarkTheme(); const [hasScrolledToLast, setHasScrolledToLast] = useState(true); - + const fetchStream = useRef(new AbortController()) useEffect(() => { scrollIntoView(); }, [queries.length, queries[queries.length - 1]]); @@ -37,7 +38,13 @@ export default function Conversation() { element.focus(); } }, []); - + useEffect(()=>{ + console.log('changed the conversation', conversationId) + return ()=>{ + console.log('i just did abortion !'); + fetchStream.current.abort(); + } + },[conversationId]) useEffect(() => { const observerCallback: IntersectionObserverCallback = (entries) => { entries.forEach((entry) => { @@ -65,13 +72,17 @@ export default function Conversation() { }); }; + fetchStream.current != null && useEffect(()=>{ + return ()=>{fetchStream.current.abort()} + },[selectConversationId]) const handleQuestion = (question: string) => { question = question.trim(); if (question === '') return; dispatch(addQuery({ prompt: question })); - dispatch(fetchAnswer({ question })); - }; + //@ts-ignore + fetchStream.current = dispatch(fetchAnswer({ question })); + }; const handleFeedback = (query: Query, feedback: FEEDBACK, index: number) => { const prevFeedback = query.feedback; dispatch(updateQuery({ index, query: { feedback } })); diff --git a/frontend/src/conversation/conversationApi.ts b/frontend/src/conversation/conversationApi.ts index a01d034..b446fc1 100644 --- a/frontend/src/conversation/conversationApi.ts +++ b/frontend/src/conversation/conversationApi.ts @@ -5,6 +5,7 @@ const apiHost = import.meta.env.VITE_API_HOST || 'https://docsapi.arc53.com'; export function fetchAnswerApi( question: string, + signal:AbortSignal, apiKey: string, selectedDocs: Doc, history: Array = [], @@ -65,6 +66,7 @@ export function fetchAnswerApi( conversation_id: conversationId, prompt_id: promptId, }), + signal, }) .then((response) => { if (response.ok) { @@ -87,6 +89,7 @@ export function fetchAnswerApi( export function fetchAnswerSteaming( question: string, + signal:AbortSignal, apiKey: string, selectedDocs: Doc, history: Array = [], @@ -134,6 +137,7 @@ export function fetchAnswerSteaming( 'Content-Type': 'application/json', }, body: JSON.stringify(body), + signal }) .then((response) => { if (!response.body) throw Error('No response body'); diff --git a/frontend/src/conversation/conversationSlice.ts b/frontend/src/conversation/conversationSlice.ts index 3f840d3..c6dd1b3 100644 --- a/frontend/src/conversation/conversationSlice.ts +++ b/frontend/src/conversation/conversationSlice.ts @@ -16,17 +16,21 @@ const API_STREAMING = import.meta.env.VITE_API_STREAMING === 'true'; export const fetchAnswer = createAsyncThunk( 'fetchAnswer', - async ({ question }, { dispatch, getState }) => { + async ({ question }, { dispatch, getState, signal }) => { const state = getState() as RootState; + console.log('signal', signal); + if (state.preference) { if (API_STREAMING) { await fetchAnswerSteaming( question, + signal, state.preference.apiKey, state.preference.selectedDocs!, state.conversation.queries, state.conversation.conversationId, state.preference.prompt.id, + (event) => { const data = JSON.parse(event.data); @@ -78,6 +82,7 @@ export const fetchAnswer = createAsyncThunk( } else { const answer = await fetchAnswerApi( question, + signal, state.preference.apiKey, state.preference.selectedDocs!, state.conversation.queries, @@ -193,6 +198,7 @@ export const conversationSlice = createSlice({ state.status = 'loading'; }) .addCase(fetchAnswer.rejected, (state, action) => { + if(action.meta.aborted)return state; //ignore error state.status = 'failed'; state.queries[state.queries.length - 1].error = 'Something went wrong. Please try again later.'; diff --git a/frontend/src/hooks/index.ts b/frontend/src/hooks/index.ts index 23fec6e..8327f76 100644 --- a/frontend/src/hooks/index.ts +++ b/frontend/src/hooks/index.ts @@ -70,7 +70,7 @@ export function useDarkTheme() { useEffect(() => { // Check if dark mode preference exists in local storage - const savedMode:string | null = localStorage.getItem('selectedTheme'); + const savedMode: string | null = localStorage.getItem('selectedTheme'); // Set dark mode based on local storage preference if (savedMode === 'Dark') { @@ -83,22 +83,19 @@ export function useDarkTheme() { document.documentElement.classList.remove('dark'); } }, []); - useEffect(()=>{ - localStorage.setItem('selectedTheme',isDarkTheme ? 'Dark' : 'Light'); - if(isDarkTheme){ + useEffect(() => { + localStorage.setItem('selectedTheme', isDarkTheme ? 'Dark' : 'Light'); + if (isDarkTheme) { document.documentElement.classList.add('dark'); document.documentElement.classList.add('dark:bg-raisin-black'); } - else{ + else { document.documentElement.classList.remove('dark'); } - },[isDarkTheme]) - - // Function to toggle dark mode - const toggleTheme:any = () => { + }, [isDarkTheme]) + //method to toggle theme + const toggleTheme: any = () => { setIsDarkTheme(!isDarkTheme) - }; - return [isDarkTheme, toggleTheme]; } \ No newline at end of file