Polish
This commit is contained in:
parent
96f9dae3ea
commit
f7704da4d3
4 changed files with 49 additions and 57 deletions
|
|
@ -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));
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue