Better nlp + refactors
This commit is contained in:
parent
4320730834
commit
297396579b
5 changed files with 45 additions and 38 deletions
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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 '';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue