Better nlp + refactors

This commit is contained in:
Richard Roberson 2025-02-11 00:12:31 -07:00
parent 4320730834
commit 297396579b
5 changed files with 45 additions and 38 deletions

View file

@ -28,8 +28,9 @@ export function EPUBViewer({ className = '' }: EPUBViewerProps) {
const toc = useRef<NavItem[]>([]); const toc = useRef<NavItem[]>([]);
const locationRef = useRef<string | number>(currDocPage); const locationRef = useRef<string | number>(currDocPage);
const handleLocationChanged = useCallback((location: string | number, initial = false) => { const handleLocationChanged = useCallback((location: string | number, initial = false) => {
// Handle special 'next' and 'prev' cases // Handle special 'next' and 'prev' cases, which
if (location === 'next' && rendition.current) { if (location === 'next' && rendition.current) {
rendition.current.next(); rendition.current.next();
return; return;

View file

@ -85,8 +85,6 @@ export function EPUBProvider({ children }: { children: ReactNode }) {
*/ */
const extractPageText = useCallback(async (book: Book, rendition: Rendition): Promise<string> => { const extractPageText = useCallback(async (book: Book, rendition: Rendition): Promise<string> => {
try { try {
console.log('Extracting EPUB text from current location');
const { start, end } = rendition.location; const { start, end } = rendition.location;
if (!start?.cfi || !end?.cfi) return ''; if (!start?.cfi || !end?.cfi) return '';

View file

@ -102,7 +102,7 @@ export function TTSProvider({ children }: { children: React.ReactNode }) {
// Use custom hooks // Use custom hooks
const audioContext = useAudioContext(); const audioContext = useAudioContext();
const audioCache = useAudioCache(50); const audioCache = useAudioCache(25);
const { availableVoices, fetchVoices } = useVoiceManagement(openApiKey, openApiBaseUrl); const { availableVoices, fetchVoices } = useVoiceManagement(openApiKey, openApiBaseUrl);
// Add ref for location change handler // Add ref for location change handler
@ -120,22 +120,21 @@ export function TTSProvider({ children }: { children: React.ReactNode }) {
* State Management * State Management
*/ */
const [isPlaying, setIsPlaying] = useState(false); const [isPlaying, setIsPlaying] = useState(false);
const [isEPUB, setIsEPUB] = useState(false);
const [isProcessing, setIsProcessing] = useState(false);
const [currDocPage, setCurrDocPage] = useState<string | number>(1);
const currDocPageNumber = (!isEPUB ? parseInt(currDocPage.toString()) : 1); // PDF uses numbers only
const [currDocPages, setCurrDocPages] = useState<number>();
const [sentences, setSentences] = useState<string[]>([]); const [sentences, setSentences] = useState<string[]>([]);
const [currentIndex, setCurrentIndex] = useState(0); const [currentIndex, setCurrentIndex] = useState(0);
const [activeHowl, setActiveHowl] = useState<Howl | null>(null); const [activeHowl, setActiveHowl] = useState<Howl | null>(null);
const [isProcessing, setIsProcessing] = useState(false);
const [speed, setSpeed] = useState(voiceSpeed); const [speed, setSpeed] = useState(voiceSpeed);
const [voice, setVoice] = useState(configVoice); const [voice, setVoice] = useState(configVoice);
const [currDocPage, setCurrDocPage] = useState<string | number>(1);
const [currDocPages, setCurrDocPages] = useState<number>();
const [nextPageLoading, setNextPageLoading] = useState(false); const [nextPageLoading, setNextPageLoading] = useState(false);
// Add this state to track if we're in EPUB mode //console.log('page:', currDocPage, 'pages:', currDocPages);
const [isEPUB, setIsEPUB] = useState(false);
const currDocPageNumber = (!isEPUB ? parseInt(currDocPage.toString()) : 1);
console.log('page:', currDocPage, 'pages:', currDocPages);
/** /**
* Changes the current page by a specified amount * Changes the current page by a specified amount

View file

@ -15,35 +15,42 @@ export const preprocessSentenceForAudio = (text: string): string => {
.trim(); .trim();
}; };
const MAX_BLOCK_LENGTH = 250; // Maximum characters per block const MAX_BLOCK_LENGTH = 300; // Maximum characters per block
export const splitIntoSentences = (text: string): string[] => { export const splitIntoSentences = (text: string): string[] => {
// Preprocess the text before splitting into sentences // Split text into paragraphs first
const cleanedText = preprocessSentenceForAudio(text); const paragraphs = text.split(/\n+/);
const doc = nlp(cleanedText);
const rawSentences = doc.sentences().out('array') as string[];
const blocks: string[] = []; const blocks: string[] = [];
let currentBlock = '';
for (const sentence of rawSentences) { for (const paragraph of paragraphs) {
const trimmedSentence = sentence.trim(); if (!paragraph.trim()) continue;
// If adding this sentence would exceed the limit, start a new block // Preprocess each paragraph
if (currentBlock && (currentBlock.length + trimmedSentence.length + 1) > MAX_BLOCK_LENGTH) { const cleanedText = preprocessSentenceForAudio(paragraph);
blocks.push(currentBlock.trim()); const doc = nlp(cleanedText);
currentBlock = trimmedSentence; const rawSentences = doc.sentences().out('array') as string[];
} else {
// Add to current block with a space if not empty let currentBlock = '';
currentBlock = currentBlock
? `${currentBlock} ${trimmedSentence}` for (const sentence of rawSentences) {
: trimmedSentence; const trimmedSentence = sentence.trim();
// If adding this sentence would exceed the limit, start a new block
if (currentBlock && (currentBlock.length + trimmedSentence.length + 1) > MAX_BLOCK_LENGTH) {
blocks.push(currentBlock.trim());
currentBlock = trimmedSentence;
} else {
// Add to current block with a space if not empty
currentBlock = currentBlock
? `${currentBlock} ${trimmedSentence}`
: trimmedSentence;
}
} }
}
// Add the last block if not empty // Add the last block if not empty
if (currentBlock) { if (currentBlock) {
blocks.push(currentBlock.trim()); blocks.push(currentBlock.trim());
}
} }
return blocks; return blocks;

View file

@ -116,10 +116,12 @@ export function findBestTextMatch(
lengthDiff: Infinity, lengthDiff: Infinity,
}; };
const SPAN_SEARCH_LIMIT = 10;
for (let i = 0; i < elements.length; i++) { for (let i = 0; i < elements.length; i++) {
let combinedText = ''; let combinedText = '';
const currentElements = []; const currentElements = [];
for (let j = i; j < Math.min(i + 10, elements.length); j++) { for (let j = i; j < Math.min(i + SPAN_SEARCH_LIMIT, elements.length); j++) {
const node = elements[j]; const node = elements[j];
const newText = combinedText ? `${combinedText} ${node.text}` : node.text; const newText = combinedText ? `${combinedText} ${node.text}` : node.text;
if (newText.length > maxCombinedLength) break; if (newText.length > maxCombinedLength) break;