This commit is contained in:
Richard Roberson 2025-01-25 22:08:15 -07:00
parent 96f9dae3ea
commit f7704da4d3
4 changed files with 49 additions and 57 deletions

View file

@ -4,7 +4,7 @@ import dynamic from 'next/dynamic';
import { usePDF } from '@/contexts/PDFContext'; import { usePDF } from '@/contexts/PDFContext';
import { useParams } from 'next/navigation'; import { useParams } from 'next/navigation';
import Link from 'next/link'; import Link from 'next/link';
import { useEffect, useState } from 'react'; import { use, useCallback, useEffect, useState } from 'react';
import { PDFSkeleton } from '@/components/PDFSkeleton'; import { PDFSkeleton } from '@/components/PDFSkeleton';
import { useTTS } from '@/contexts/TTSContext'; import { useTTS } from '@/contexts/TTSContext';
@ -25,24 +25,26 @@ export default function PDFViewerPage() {
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
const [zoomLevel, setZoomLevel] = useState<number>(100); const [zoomLevel, setZoomLevel] = useState<number>(100);
useEffect(() => { const loadDocument = useCallback(async () => {
async function loadDocument() { if (!isLoading) return; // Prevent calls when not loading new doc
try { console.log('Loading new document (from page.tsx)');
if (!id) { try {
setError('Document not found'); if (!id) {
return; 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);
} }
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(); loadDocument();
}, [id, setCurrentDocument]); }, [loadDocument]);
const handleZoomIn = () => setZoomLevel(prev => Math.min(prev + 10, 200)); const handleZoomIn = () => setZoomLevel(prev => Math.min(prev + 10, 200));
const handleZoomOut = () => setZoomLevel(prev => Math.max(prev - 10, 50)); const handleZoomOut = () => setZoomLevel(prev => Math.max(prev - 10, 50));

View file

@ -8,8 +8,6 @@ import { useState, useEffect, useRef } from 'react';
import { PDFSkeleton } from './PDFSkeleton'; import { PDFSkeleton } from './PDFSkeleton';
import { useTTS } from '@/contexts/TTSContext'; import { useTTS } from '@/contexts/TTSContext';
import { usePDF } from '@/contexts/PDFContext'; 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'; import TTSPlayer from '@/components/player/TTSPlayer';
interface PDFViewerProps { interface PDFViewerProps {

View file

@ -51,7 +51,6 @@ interface PDFContextType {
isProcessing: boolean isProcessing: boolean
) => void; ) => void;
onDocumentLoadSuccess: ({ numPages }: { numPages: number }) => void; onDocumentLoadSuccess: ({ numPages }: { numPages: number }) => void;
convertPDFDataToURL: (pdfData: Blob) => Promise<string>;
setCurrentDocument: (id: string) => Promise<void>; setCurrentDocument: (id: string) => Promise<void>;
currDocURL: string | undefined; currDocURL: string | undefined;
currDocName: string | undefined; currDocName: string | undefined;
@ -267,7 +266,7 @@ export function PDFProvider({ children }: { children: ReactNode }) {
console.error('Failed to get document URL:', error); console.error('Failed to get document URL:', error);
setError('Failed to retrieve the document. Please try again.'); setError('Failed to retrieve the document. Please try again.');
} }
}, [getDocument, convertPDFDataToURL, loadCurrDocText]); }, [getDocument, loadCurrDocText]);
// Clear all highlights in the PDF viewer // Clear all highlights in the PDF viewer
const clearHighlights = useCallback(() => { const clearHighlights = useCallback(() => {
@ -458,7 +457,6 @@ export function PDFProvider({ children }: { children: ReactNode }) {
clearHighlights, clearHighlights,
handleTextClick, handleTextClick,
onDocumentLoadSuccess, onDocumentLoadSuccess,
convertPDFDataToURL,
setCurrentDocument, setCurrentDocument,
currDocURL, currDocURL,
currDocName, currDocName,
@ -478,7 +476,6 @@ export function PDFProvider({ children }: { children: ReactNode }) {
clearHighlights, clearHighlights,
handleTextClick, handleTextClick,
onDocumentLoadSuccess, onDocumentLoadSuccess,
convertPDFDataToURL,
setCurrentDocument, setCurrentDocument,
currDocURL, currDocURL,
currDocName, currDocName,

View file

@ -89,11 +89,9 @@ export function TTSProvider({ children }: { children: React.ReactNode }) {
console.log('Setting page text:', text); console.log('Setting page text:', text);
const newSentences = splitIntoSentences(text); const newSentences = splitIntoSentences(text);
setSentences(newSentences); setSentences(newSentences);
//setCurrentIndex(0);
//setIsPlaying(false);
// Clear audio cache // Clear audio cache
audioCacheRef.current.clear(); //audioCacheRef.current.clear();
setNextPageLoading(false); setNextPageLoading(false);
}, []); }, []);
@ -116,35 +114,51 @@ export function TTSProvider({ children }: { children: React.ReactNode }) {
}); });
}, [abortAudio]); }, [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(() => { const skipForward = useCallback(() => {
setIsProcessing(true); setIsProcessing(true);
abortAudio(); abortAudio();
setCurrentIndex((prev) => { advance();
const nextIndex = Math.min(prev + 1, sentences.length - 1);
console.log('Skipping forward to:', sentences[nextIndex]);
return nextIndex;
});
setIsProcessing(false); setIsProcessing(false);
}, [sentences, abortAudio]); }, [abortAudio, advance]);
const skipBackward = useCallback(() => { const skipBackward = useCallback(() => {
setIsProcessing(true); setIsProcessing(true);
abortAudio(); abortAudio();
setCurrentIndex((prev) => { advance(true); // Pass true to go backwards
const nextIndex = Math.max(prev - 1, 0);
console.log('Skipping backward to:', sentences[nextIndex]);
return nextIndex;
});
setIsProcessing(false); setIsProcessing(false);
}, [sentences, abortAudio]); }, [abortAudio, advance]);
// Initialize OpenAI instance when config loads // Initialize OpenAI instance when config loads
useEffect(() => { useEffect(() => {
@ -229,30 +243,12 @@ export function TTSProvider({ children }: { children: React.ReactNode }) {
} }
}, [togglePlay, skipForward, skipBackward]); }, [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 //new function to return audio buffer with caching
const getAudio = useCallback(async (sentence: string): Promise<AudioBuffer | undefined> => { const getAudio = useCallback(async (sentence: string): Promise<AudioBuffer | undefined> => {
// Check if the audio is already cached // Check if the audio is already cached
const cachedAudio = audioCacheRef.current.get(sentence); const cachedAudio = audioCacheRef.current.get(sentence);
if (cachedAudio) { if (cachedAudio) {
console.log('Using cached audio for sentence:', sentence); console.log('Using cached audio for sentence:', sentence.substring(0, 20));
return cachedAudio; return cachedAudio;
} }
@ -350,7 +346,6 @@ export function TTSProvider({ children }: { children: React.ReactNode }) {
const preloadNextAudio = useCallback(() => { const preloadNextAudio = useCallback(() => {
try { try {
if (sentences[currentIndex + 1] && !audioCacheRef.current.has(sentences[currentIndex + 1])) { 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 processSentence(sentences[currentIndex + 1], true); // True indicates preloading
} }
} catch (error) { } catch (error) {