+
+
+
+ {speed}x
+
+
+
+ {speedOptions.map((option) => (
+
+ `relative cursor-pointer select-none py-2 px-3 ${active ? 'bg-offbase' : ''
+ } ${selected ? 'font-medium' : ''}`
+ }
+ >
+ {option.label}
+
+ ))}
+
+
+
+
-
+
:
}
-
-
-
- {speed}x
-
-
-
- {speedOptions.map((option) => (
-
- `relative cursor-pointer select-none py-2 px-3 ${
- active ? 'bg-offbase' : ''
- } ${selected ? 'font-medium' : ''}`
- }
- >
- {option.label}
-
- ))}
-
-
-
@@ -117,10 +116,8 @@ export default function TTSPlayer() {
- `relative cursor-pointer select-none py-2 px-3 ${
- active ? 'bg-offbase' : ''
- } ${selected ? 'font-medium' : ''}`
+ className={({ active, selected }) =>
+ `relative cursor-pointer select-none py-2 px-3 ${active ? 'bg-offbase' : ''} ${selected ? 'font-medium' : ''}`
}
>
{voiceId}
diff --git a/src/contexts/PDFContext.tsx b/src/contexts/PDFContext.tsx
index 2d6a1c3..06fb524 100644
--- a/src/contexts/PDFContext.tsx
+++ b/src/contexts/PDFContext.tsx
@@ -15,6 +15,9 @@ import { pdfjs } from 'react-pdf';
import stringSimilarity from 'string-similarity';
import nlp from 'compromise';
+// Add the correct type import
+import type { TextContent, TextItem } from 'pdfjs-dist/types/src/display/api';
+
// Set worker from public directory
pdfjs.GlobalWorkerOptions.workerSrc = '/pdf.worker.mjs';
@@ -135,11 +138,66 @@ export function PDFProvider({ children }: { children: ReactNode }) {
for (let i = 1; i <= pdf.numPages; i++) {
const page = await pdf.getPage(i);
const textContent = await page.getTextContent();
- const pageText = textContent.items.map((item: any) => item.str).join(' ');
- fullText += pageText + ' ';
+
+ // Filter out non-text items and assert proper type
+ const textItems = textContent.items.filter((item): item is TextItem =>
+ 'str' in item && 'transform' in item
+ );
+
+ // Group text items into lines based on their vertical position
+ const tolerance = 2;
+ const lines: TextItem[][] = [];
+ let currentLine: TextItem[] = [];
+ let currentY: number | null = null;
+
+ textItems.forEach((item) => {
+ const y = item.transform[5];
+ if (currentY === null) {
+ currentY = y;
+ currentLine.push(item);
+ } else if (Math.abs(y - currentY) < tolerance) {
+ currentLine.push(item);
+ } else {
+ lines.push(currentLine);
+ currentLine = [item];
+ currentY = y;
+ }
+ });
+ lines.push(currentLine);
+
+ // Process each line to build text
+ let pageText = '';
+ for (const line of lines) {
+ // Sort items horizontally within the line
+ line.sort((a, b) => a.transform[4] - b.transform[4]);
+
+ let lineText = '';
+ let prevItem: TextItem | null = null;
+
+ for (const item of line) {
+ if (!prevItem) {
+ lineText = item.str;
+ } else {
+ const prevEndX = prevItem.transform[4] + (prevItem.width ?? 0);
+ const currentStartX = item.transform[4];
+ const space = currentStartX - prevEndX;
+
+ // Add space if gap is significant, otherwise concatenate directly
+ if (space > ((item.width ?? 0) * 0.3)) {
+ lineText += ' ' + item.str;
+ } else {
+ lineText += item.str;
+ }
+ }
+ prevItem = item;
+ }
+ pageText += lineText + ' ';
+ }
+
+ fullText += pageText + '\n';
}
- return fullText;
+ return fullText.replace(/\s+/g, ' ').trim();
} catch (error) {
console.error('Error extracting text from PDF:', error);
throw new Error('Failed to extract text from PDF');