From f7704da4d3bd3877125d0acdf03fe77660f79894 Mon Sep 17 00:00:00 2001 From: Richard Roberson Date: Sat, 25 Jan 2025 22:08:15 -0700 Subject: [PATCH] Polish --- src/app/pdf/[id]/page.tsx | 32 +++++++++-------- src/components/PDFViewer.tsx | 2 -- src/contexts/PDFContext.tsx | 5 +-- src/contexts/TTSContext.tsx | 67 +++++++++++++++++------------------- 4 files changed, 49 insertions(+), 57 deletions(-) diff --git a/src/app/pdf/[id]/page.tsx b/src/app/pdf/[id]/page.tsx index 44b524e..6d6cedf 100644 --- a/src/app/pdf/[id]/page.tsx +++ b/src/app/pdf/[id]/page.tsx @@ -4,7 +4,7 @@ import dynamic from 'next/dynamic'; import { usePDF } from '@/contexts/PDFContext'; import { useParams } from 'next/navigation'; import Link from 'next/link'; -import { useEffect, useState } from 'react'; +import { use, useCallback, useEffect, useState } from 'react'; import { PDFSkeleton } from '@/components/PDFSkeleton'; import { useTTS } from '@/contexts/TTSContext'; @@ -25,24 +25,26 @@ export default function PDFViewerPage() { const [isLoading, setIsLoading] = useState(true); const [zoomLevel, setZoomLevel] = useState(100); - useEffect(() => { - async function loadDocument() { - try { - if (!id) { - setError('Document not found'); - return; - } - setCurrentDocument(id as string); - } catch (err) { - console.error('Error loading document:', err); - setError('Failed to load document'); - } finally { - setIsLoading(false); + const loadDocument = useCallback(async () => { + if (!isLoading) return; // Prevent calls when not loading new doc + console.log('Loading new document (from page.tsx)'); + try { + if (!id) { + setError('Document not found'); + return; } + setCurrentDocument(id as string); + } catch (err) { + console.error('Error loading document:', err); + setError('Failed to load document'); + } finally { + setIsLoading(false); } + }, [isLoading, id, setCurrentDocument]); + useEffect(() => { loadDocument(); - }, [id, setCurrentDocument]); + }, [loadDocument]); const handleZoomIn = () => setZoomLevel(prev => Math.min(prev + 10, 200)); const handleZoomOut = () => setZoomLevel(prev => Math.max(prev - 10, 50)); diff --git a/src/components/PDFViewer.tsx b/src/components/PDFViewer.tsx index 6f38afd..d00af3b 100644 --- a/src/components/PDFViewer.tsx +++ b/src/components/PDFViewer.tsx @@ -8,8 +8,6 @@ import { useState, useEffect, useRef } from 'react'; import { PDFSkeleton } from './PDFSkeleton'; import { useTTS } from '@/contexts/TTSContext'; import { usePDF } from '@/contexts/PDFContext'; -import { pdfjs } from 'react-pdf'; -import type { TextItem } from 'pdfjs-dist/types/src/display/api'; import TTSPlayer from '@/components/player/TTSPlayer'; interface PDFViewerProps { diff --git a/src/contexts/PDFContext.tsx b/src/contexts/PDFContext.tsx index 1810f02..bcf68c6 100644 --- a/src/contexts/PDFContext.tsx +++ b/src/contexts/PDFContext.tsx @@ -51,7 +51,6 @@ interface PDFContextType { isProcessing: boolean ) => void; onDocumentLoadSuccess: ({ numPages }: { numPages: number }) => void; - convertPDFDataToURL: (pdfData: Blob) => Promise; setCurrentDocument: (id: string) => Promise; currDocURL: string | undefined; currDocName: string | undefined; @@ -267,7 +266,7 @@ export function PDFProvider({ children }: { children: ReactNode }) { console.error('Failed to get document URL:', error); setError('Failed to retrieve the document. Please try again.'); } - }, [getDocument, convertPDFDataToURL, loadCurrDocText]); + }, [getDocument, loadCurrDocText]); // Clear all highlights in the PDF viewer const clearHighlights = useCallback(() => { @@ -458,7 +457,6 @@ export function PDFProvider({ children }: { children: ReactNode }) { clearHighlights, handleTextClick, onDocumentLoadSuccess, - convertPDFDataToURL, setCurrentDocument, currDocURL, currDocName, @@ -478,7 +476,6 @@ export function PDFProvider({ children }: { children: ReactNode }) { clearHighlights, handleTextClick, onDocumentLoadSuccess, - convertPDFDataToURL, setCurrentDocument, currDocURL, currDocName, diff --git a/src/contexts/TTSContext.tsx b/src/contexts/TTSContext.tsx index 5021ba3..f3669b4 100644 --- a/src/contexts/TTSContext.tsx +++ b/src/contexts/TTSContext.tsx @@ -89,11 +89,9 @@ export function TTSProvider({ children }: { children: React.ReactNode }) { console.log('Setting page text:', text); const newSentences = splitIntoSentences(text); setSentences(newSentences); - //setCurrentIndex(0); - //setIsPlaying(false); // Clear audio cache - audioCacheRef.current.clear(); + //audioCacheRef.current.clear(); setNextPageLoading(false); }, []); @@ -115,6 +113,31 @@ export function TTSProvider({ children }: { children: React.ReactNode }) { } }); }, [abortAudio]); + + const advance = useCallback(async (backwards = false) => { + setCurrentIndex((prev) => { + const nextIndex = prev + (backwards ? -1 : 1); + if (nextIndex < sentences.length && nextIndex >= 0) { + console.log('Advancing to next sentence:', sentences[nextIndex]); + return nextIndex; + } else if (nextIndex >= sentences.length && currDocPage < currDocPages!) { + console.log('Advancing to next page:', currDocPage + 1); + + setNextPageLoading(true); + setCurrDocPage(currDocPage + 1); + + return 0; + } else if (nextIndex < 0 && currDocPage > 1) { + console.log('Advancing to previous page:', currDocPage - 1); + + setNextPageLoading(true); + setCurrDocPage(currDocPage - 1); + + return 0; + } + return prev; + }); + }, [sentences, currDocPage, currDocPages]); const skipForward = useCallback(() => { @@ -122,29 +145,20 @@ export function TTSProvider({ children }: { children: React.ReactNode }) { abortAudio(); - setCurrentIndex((prev) => { - const nextIndex = Math.min(prev + 1, sentences.length - 1); - console.log('Skipping forward to:', sentences[nextIndex]); - return nextIndex; - }); + advance(); setIsProcessing(false); - }, [sentences, abortAudio]); + }, [abortAudio, advance]); const skipBackward = useCallback(() => { setIsProcessing(true); abortAudio(); - setCurrentIndex((prev) => { - const nextIndex = Math.max(prev - 1, 0); - console.log('Skipping backward to:', sentences[nextIndex]); - return nextIndex; - }); - + advance(true); // Pass true to go backwards setIsProcessing(false); - }, [sentences, abortAudio]); + }, [abortAudio, advance]); // Initialize OpenAI instance when config loads useEffect(() => { @@ -229,30 +243,12 @@ export function TTSProvider({ children }: { children: React.ReactNode }) { } }, [togglePlay, skipForward, skipBackward]); - const advance = useCallback(async () => { - setCurrentIndex((prev) => { - const nextIndex = prev + 1; - if (nextIndex < sentences.length) { - console.log('Auto-advancing to next sentence:', sentences[nextIndex]); - return nextIndex; - } else if (currDocPage < currDocPages!) { - console.log('Auto-advancing to next page:', currDocPage + 1); - - setNextPageLoading(true); - setCurrDocPage(currDocPage + 1); - - return 0; - } - return prev; - }); - }, [sentences, currDocPage, currDocPages]); - //new function to return audio buffer with caching const getAudio = useCallback(async (sentence: string): Promise => { // Check if the audio is already cached const cachedAudio = audioCacheRef.current.get(sentence); if (cachedAudio) { - console.log('Using cached audio for sentence:', sentence); + console.log('Using cached audio for sentence:', sentence.substring(0, 20)); return cachedAudio; } @@ -350,7 +346,6 @@ export function TTSProvider({ children }: { children: React.ReactNode }) { const preloadNextAudio = useCallback(() => { try { if (sentences[currentIndex + 1] && !audioCacheRef.current.has(sentences[currentIndex + 1])) { - //await new Promise((resolve) => setTimeout(resolve, 200)); // Add small delay processSentence(sentences[currentIndex + 1], true); // True indicates preloading } } catch (error) {