From 78fbd65fc1f1d2622ca7dbc782b828218fe5eda3 Mon Sep 17 00:00:00 2001 From: Amrit Krishnan Date: Thu, 3 Oct 2024 16:17:36 -0400 Subject: [PATCH] Fixes for reloading from database --- ui/src/app/answer/[id]/page.tsx | 242 +++++++++++++++++++------------- ui/src/app/home/page.tsx | 12 +- 2 files changed, 150 insertions(+), 104 deletions(-) diff --git a/ui/src/app/answer/[id]/page.tsx b/ui/src/app/answer/[id]/page.tsx index 6148d77..06da48d 100644 --- a/ui/src/app/answer/[id]/page.tsx +++ b/ui/src/app/answer/[id]/page.tsx @@ -1,7 +1,7 @@ 'use client' -import React, { useEffect, useState, useCallback, useRef } from 'react' -import { useParams, useRouter } from 'next/navigation' +import React, { useEffect, useState, useCallback } from 'react' +import { useParams, useRouter, useSearchParams } from 'next/navigation' import { Box, Flex, VStack, useColorModeValue, Container, Card, CardBody, useToast, Skeleton, Text, Heading, Progress @@ -15,16 +15,25 @@ import StepsCard from '../../components/steps-card' const MotionBox = motion & MotionProps, "transition">>(Box) +interface Step { + step: string; + reasoning: string; +} + +interface Query { + query: string; + patient_id?: number; + steps?: Step[]; +} + +interface Answer { + answer: string; + reasoning: string; +} + interface QueryAnswer { - query: { - query: string; - patient_id?: number; - steps?: Array<{ step: string; reasoning: string }>; - }; - answer?: { - answer: string; - reasoning: string; - }; + query: Query; + answer?: Answer; is_first: boolean; } @@ -42,25 +51,55 @@ const AnswerPage: React.FC = () => { const [isGeneratingSteps, setIsGeneratingSteps] = useState(false) const [isGeneratingAnswer, setIsGeneratingAnswer] = useState(false) const params = useParams() + const searchParams = useSearchParams() const id = params?.id as string + const isNewQuery = searchParams?.get('new') === 'true' const router = useRouter() const toast = useToast() - const generationStartedRef = useRef(false) - const bgColor = useColorModeValue('gray.50', 'gray.900') const cardBgColor = useColorModeValue('white', 'gray.800') - const generateStepsAndAnswer = useCallback(async (query: string, patientId?: number) => { - if (generationStartedRef.current) return - generationStartedRef.current = true - setIsGeneratingSteps(true) + const fetchPageData = useCallback(async (): Promise => { + setIsLoading(true) + try { + const token = localStorage.getItem('token') + if (!token) throw new Error('No token found') + + const response = await fetch(`/api/pages/${id}`, { + headers: { 'Authorization': `Bearer ${token}` }, + }) + + if (!response.ok) { + const errorData = await response.json() + throw new Error(`Failed to fetch page data: ${errorData.message}`) + } + const data: PageData = await response.json() + setPageData(data) + return data + } catch (error) { + console.error('Error loading page data:', error) + toast({ + title: "Error", + description: error instanceof Error ? error.message : "An error occurred while loading page data", + status: "error", + duration: 3000, + isClosable: true, + }) + return null + } finally { + setIsLoading(false) + } + }, [id, toast]) + + + const generateSteps = useCallback(async (query: string, patientId?: number): Promise => { + setIsGeneratingSteps(true) try { const token = localStorage.getItem('token') if (!token) throw new Error('No token found') - // Generate steps const stepsResponse = await fetch('/api/generate_cot_steps', { method: 'POST', headers: { @@ -71,26 +110,33 @@ const AnswerPage: React.FC = () => { }) if (!stepsResponse.ok) { - throw new Error('Failed to generate steps') + const errorData = await stepsResponse.json() + throw new Error(`Failed to generate steps: ${errorData.message}`) } const stepsData = await stepsResponse.json() - - setPageData(prevData => { - if (!prevData) return null - const updatedQueryAnswers = prevData.query_answers.map(qa => { - if (qa.is_first) { - return { ...qa, query: { ...qa.query, steps: stepsData.cot_steps } } - } - return qa - }) - return { ...prevData, query_answers: updatedQueryAnswers } + return stepsData.cot_steps + } catch (error) { + console.error('Error generating steps:', error) + toast({ + title: "Error", + description: error instanceof Error ? error.message : "An error occurred while generating steps", + status: "error", + duration: 3000, + isClosable: true, }) - + return null + } finally { setIsGeneratingSteps(false) - setIsGeneratingAnswer(true) + } + }, [toast]) + + const generateAnswer = useCallback(async (query: string, patientId?: number, steps?: Step[]): Promise => { + setIsGeneratingAnswer(true) + try { + const token = localStorage.getItem('token') + if (!token) throw new Error('No token found') - // Generate answer const answerResponse = await fetch('/api/generate_cot_answer', { method: 'POST', headers: { @@ -100,86 +146,60 @@ const AnswerPage: React.FC = () => { body: JSON.stringify({ query, patient_id: patientId, - steps: stepsData.cot_steps + steps }), }) if (!answerResponse.ok) { - throw new Error('Failed to generate answer') + const errorData = await answerResponse.json() + throw new Error(`Failed to generate answer: ${errorData.message}`) } const answerData = await answerResponse.json() - - setPageData(prevData => { - if (!prevData) return null - const updatedQueryAnswers = prevData.query_answers.map(qa => { - if (qa.is_first) { - return { ...qa, answer: answerData } - } - return qa - }) - return { ...prevData, query_answers: updatedQueryAnswers } - }) - + return answerData } catch (error) { - console.error('Error:', error) + console.error('Error generating answer:', error) toast({ title: "Error", - description: error instanceof Error ? error.message : "An error occurred while generating steps and answer", + description: error instanceof Error ? error.message : "An error occurred while generating the answer", status: "error", duration: 3000, isClosable: true, }) + return null } finally { - setIsGeneratingSteps(false) setIsGeneratingAnswer(false) } }, [toast]) - useEffect(() => { - const fetchPageData = async () => { - setIsLoading(true) - try { - const token = localStorage.getItem('token') - if (!token) throw new Error('No token found') - - const response = await fetch(`/api/pages/${id}`, { - headers: { 'Authorization': `Bearer ${token}` }, - }) - - if (!response.ok) { - throw new Error('Failed to fetch page data') - } - - const data: PageData = await response.json() - setPageData(data) - setIsLoading(false) + const [hasGeneratedAnswer, setHasGeneratedAnswer] = useState(false) - const firstQueryAnswer = data.query_answers.find(qa => qa.is_first) + useEffect(() => { + const initializePage = async () => { + const data = await fetchPageData() + if (data && isNewQuery) { + const firstQueryAnswer = data.query_answers[0] if (firstQueryAnswer && !firstQueryAnswer.query.steps) { - await generateStepsAndAnswer(firstQueryAnswer.query.query, firstQueryAnswer.query.patient_id) + const steps = await generateSteps(firstQueryAnswer.query.query, firstQueryAnswer.query.patient_id) + if (steps) { + const answer = await generateAnswer(firstQueryAnswer.query.query, firstQueryAnswer.query.patient_id, steps) + if (answer) { + setPageData(prevData => { + if (!prevData) return data + const updatedQueryAnswers = [ + { ...firstQueryAnswer, query: { ...firstQueryAnswer.query, steps }, answer }, + ...prevData.query_answers.slice(1) + ] + return { ...prevData, query_answers: updatedQueryAnswers } + }) + } + } } - } catch (error) { - console.error('Error loading page data:', error) - toast({ - title: "Error", - description: error instanceof Error ? error.message : "An error occurred while loading page data", - status: "error", - duration: 3000, - isClosable: true, - }) - setIsLoading(false) } } - if (id) { - fetchPageData() - } - - return () => { - generationStartedRef.current = false - } - }, [id, generateStepsAndAnswer, toast]) + initializePage() + }, [fetchPageData, generateSteps, generateAnswer, isNewQuery]) const handleSearch = async (query: string) => { if (!query.trim()) { @@ -197,22 +217,48 @@ const AnswerPage: React.FC = () => { const token = localStorage.getItem('token') if (!token) throw new Error('No token found') - const createPageResponse = await fetch('/api/pages/create', { + // Append the new query to the existing page + const appendResponse = await fetch(`/api/pages/${id}/append`, { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json', }, - body: JSON.stringify({ query }), + body: JSON.stringify({ question: query }), }) - if (!createPageResponse.ok) { - throw new Error('Failed to create new page') + if (!appendResponse.ok) { + const errorData = await appendResponse.json() + throw new Error(`Failed to append to page: ${errorData.message}`) } - const { page_id } = await createPageResponse.json() + // Generate steps for the new query + setIsGeneratingSteps(true) + const steps = await generateSteps(query) + setIsGeneratingSteps(false) - router.push(`/answer/${page_id}`) + if (steps) { + // Generate answer using the steps + setIsGeneratingAnswer(true) + const answer = await generateAnswer(query, undefined, steps) + setIsGeneratingAnswer(false) + + if (answer) { + // Update the page data with the new query, steps, and answer + setPageData(prevData => { + if (!prevData) return null + const updatedQueryAnswers = [ + ...prevData.query_answers, + { + query: { query, steps }, + answer, + is_first: false + } + ] + return { ...prevData, query_answers: updatedQueryAnswers } + }) + } + } } catch (error) { console.error('Error:', error) toast({ @@ -225,7 +271,7 @@ const AnswerPage: React.FC = () => { } } - const firstQueryAnswer = pageData?.query_answers.find(qa => qa.is_first) + const firstQueryAnswer = pageData?.query_answers[0] return ( @@ -318,11 +364,9 @@ const AnswerPage: React.FC = () => { )} - {!pageData && ( - - - - )} + + + diff --git a/ui/src/app/home/page.tsx b/ui/src/app/home/page.tsx index d9bd88f..4fbba9a 100644 --- a/ui/src/app/home/page.tsx +++ b/ui/src/app/home/page.tsx @@ -9,6 +9,10 @@ import Sidebar from '../components/sidebar' import { withAuth } from '../components/with-auth' import SearchBox from '../components/search-box' +interface CreatePageResponse { + page_id: string; +} + const HomePage: React.FC = () => { const [isLoading, setIsLoading] = useState(false) const router = useRouter() @@ -43,14 +47,13 @@ const HomePage: React.FC = () => { } router.push(`/patient/${patientId}`) } else { - // Create a new page const createPageResponse = await fetch('/api/pages/create', { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json', }, - body: JSON.stringify({ query: query }), + body: JSON.stringify({ query }), }) if (!createPageResponse.ok) { @@ -58,11 +61,10 @@ const HomePage: React.FC = () => { throw new Error(`Failed to create new page: ${JSON.stringify(errorData)}`); } - const { page_id } = await createPageResponse.json() + const { page_id }: CreatePageResponse = await createPageResponse.json() if (page_id) { - // Redirect to the new page - router.push(`/answer/${page_id}`) + router.push(`/answer/${page_id}?new=true`) } else { throw new Error('Failed to get page ID') }