Skip to content

Commit 422da3a

Browse files
committed
Dcument extraction documented
1 parent 1963bc9 commit 422da3a

4 files changed

Lines changed: 74 additions & 3 deletions

File tree

‎docs/feature-reference.md‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,11 @@ During transfer:
7878
### Diagrams & Media Gallery
7979

8080
Open via **Workspace -> Diagrams & Media Gallery** (`Ctrl/Cmd + Alt + M`) or Command Palette:
81-
- Catalogs all used diagrams (inline Mermaid, Draw.io, Excalidraw, Wireframe UI prototypes), images, videos, audio, and PDF documents in the workspace.
81+
- Catalogs all used diagrams (inline Mermaid, Draw.io, Excalidraw, Wireframe UI prototypes), images, videos, audio, and PDF/Office documents in the workspace.
8282
- **Physical Disk Scanner & Orphan Detection**: Scans workspace folders (`media/`, `assets/`, `images/`, `media/wireframes/`, `media/draw.io/`) to identify files present on disk that have zero note references.
8383
- **Unused Media Filter**: Quickly isolate unreferenced assets with the `⚠️ Unused / Orphans` filter tab.
84+
- **Automated Document Extraction**: Extracts and caches clean structured Markdown from Word (`.docx`), Excel (`.xlsx`, `.xls`, `.csv`), PowerPoint (`.pptx`), and PDF (`.pdf`) files with table preservation and spatial clustering.
85+
- **Tabbed Media & Extracted Viewer**: Switch between native preview and formatted extracted reading view with in-document search, line-numbered raw view, copy/download tools, and metadata chips.
8486
- **Audio & Media Preview**: Embedded audio players, video thumbnails, and transcript drawer with key points and action items.
8587
- **UI Prototypes & Wireframe Studio**: View, inspect references, and launch Wireframe Studio to edit interactive UI mockups directly.
8688
- Reuses Knowledge Graph layout aesthetics with collapsible category filters, search, and stat indicators.

‎docs/workspace/media.md‎

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,30 @@ Keep your assets tidy using the Media Health Dashboard:
3939
## 4. Diagrams & Media Asset Manager
4040

4141
Notely provides a dedicated full-screen asset manager under **Workspace > Diagrams & Media** (shortcut: `Ctrl+Alt+M` or `Cmd+Alt+M`):
42-
- **Dense Asset Table Layout**: High-density table displaying Asset Name, Type Badge, File Size, Reference Status, and Quick Action buttons.
42+
- **Dense Asset Table Layout**: High-density table displaying Asset Name, Type Badge, File Size, Reference Status, Extraction Status, and Quick Action buttons.
4343
- **Fixed Sidebar & Category Filters**: Left sidebar (260px) with real-time counters for Diagrams, UI Prototypes, Images, PDFs, Videos, Audio, Transcripts, and Documents.
4444
- **Physical Disk Scanner & Orphan Detection**: Discovers assets on disk across `media/`, `assets/`, and `images/`. Unreferenced assets are highlighted with the `⚠️ Unused / Orphans` badge and filter tab.
4545
- **Asset Bundles**: Audio and video recordings are organized into bundle folders (`media/audio/<id>/` and `media/video/<id>/`) containing the primary recording alongside companion `transcript.json`.
4646
- **Integrated Full-Screen Media Viewer**: Standardized modal viewer with 100% full-width layout, subtitle/transcript side drawer, playback speed controls, and copy/download tools.
4747
- **Safe Asset Deletion**: Remove unwanted assets with safety confirmation modals that check note references and warn before removing actively linked files.
4848
- **Referenced Notes & Line Jumping**: Inspect reference pills to view note names, line numbers, and markdown context snippets, with 1-click navigation to jump directly to the editor position.
49+
50+
---
51+
52+
## 5. Document Text Extraction & Caching
53+
54+
Notely features an automated, background document extraction and indexing engine for office documents and PDFs:
55+
56+
### Supported Formats
57+
- **Word Documents (`.docx`)**: OpenXML parsing extracting headings, paragraphs, bulleted/numbered lists, and tables as standard Markdown.
58+
- **Spreadsheets (`.xlsx`, `.xls`, `.csv`)**: SheetJS-powered table extraction preserving multi-sheet workbooks (`### Sheet: Name`) into GFM Markdown tables.
59+
- **Presentations (`.pptx`)**: Slide-by-slide text hierarchy extraction (`### Slide N: Title`) including presenter speaker notes.
60+
- **PDF Documents (`.pdf`)**: Spatial line clustering and page-segmented Markdown extraction (`### Page N`).
61+
62+
### Unified Tabbed Preview
63+
When inspecting or previewing supported documents in the gallery or editor:
64+
- **`[ Preview | Extracted Text ]` Switcher**: Seamlessly toggle between native rendering and the extracted text view.
65+
- **Formatted Reading View**: Formatted paper sheet view with typography, scrollable tables, reading time estimation, and metadata pills (page count, word count, SHA-256 content hash).
66+
- **Markdown Source View**: Synchronized line-numbered raw markdown editor with copy, download, and re-extraction actions.
67+
- **In-Document Search**: Instant search bar with occurrence counting and keyword highlights across both reading view and raw source lines.
68+
- **Persistent Caching**: Document hashes and extracted text are stored in `.notes-app/documents.db` and `.notes-app/extracted/` so subsequent reads are instant without re-parsing.

‎package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
"node-pty": "^1.1.0",
5151
"onnxruntime-node": "^1.27.0",
5252
"onnxruntime-web": "^1.27.0",
53+
"pdfjs-dist": "^4.3.136",
5354
"simple-git": "^3.36.0",
5455
"tree-sitter-wasms": "^0.1.13",
5556
"uuid": "^14.0.1",
@@ -88,7 +89,6 @@
8889
"markdownlint-cli2": "^0.18.1",
8990
"mermaid": "^11.6.0",
9091
"nspell": "^2.1.5",
91-
"pdfjs-dist": "^4.3.136",
9292
"png-to-ico": "^2.1.8",
9393
"pngjs": "^7.0.0",
9494
"prettier": "^3.4.0",

‎tests/documentExtractors.test.js‎

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import * as XLSX from 'xlsx';
88
const { extractDocx } = require('../electron/lib/extractors/DocxExtractor.cjs');
99
const { extractPptx } = require('../electron/lib/extractors/PptxExtractor.cjs');
1010
const { extractSpreadsheet } = require('../electron/lib/extractors/SpreadsheetExtractor.cjs');
11+
const { extractPdf } = require('../electron/lib/extractors/PdfExtractor.cjs');
12+
const { extractDocument, isSupportedDocument, getDocumentMimeType } = require('../electron/lib/extractors/DocumentExtractor.cjs');
1113
const { DocumentCacheStore } = require('../electron/lib/documents/DocumentCacheStore.cjs');
1214
const { DocumentExtractionService } = require('../electron/services/DocumentExtractionService.cjs');
1315

@@ -224,4 +226,51 @@ describe('Document Extractors & Cache Pipeline', () => {
224226
service.close();
225227
});
226228
});
229+
230+
describe('PdfExtractor & Error Handling', () => {
231+
it('handles non-existent PDF files gracefully', async () => {
232+
const result = await extractPdf(path.join(tempDir, 'missing.pdf'));
233+
expect(result.success).toBe(false);
234+
expect(result.status).toBe('failed');
235+
expect(result.error).toContain('File not found');
236+
});
237+
238+
it('handles corrupted/empty PDF files gracefully', async () => {
239+
const corruptedPath = path.join(tempDir, 'corrupt.pdf');
240+
fs.writeFileSync(corruptedPath, 'Not a real PDF stream header');
241+
const result = await extractPdf(corruptedPath);
242+
expect(result.success).toBe(false);
243+
expect(result.status).toBe('failed');
244+
});
245+
});
246+
247+
describe('DocumentExtractor Dispatcher', () => {
248+
it('identifies supported document file types', () => {
249+
expect(isSupportedDocument('report.pdf')).toBe(true);
250+
expect(isSupportedDocument('doc.docx')).toBe(true);
251+
expect(isSupportedDocument('slides.pptx')).toBe(true);
252+
expect(isSupportedDocument('data.xlsx')).toBe(true);
253+
expect(isSupportedDocument('data.csv')).toBe(true);
254+
expect(isSupportedDocument('image.png')).toBe(false);
255+
expect(isSupportedDocument('audio.mp3')).toBe(false);
256+
});
257+
258+
it('returns appropriate MIME types for supported documents', () => {
259+
expect(getDocumentMimeType('report.pdf')).toBe('application/pdf');
260+
expect(getDocumentMimeType('doc.docx')).toBe('application/vnd.openxmlformats-officedocument.wordprocessingml.document');
261+
expect(getDocumentMimeType('slides.pptx')).toBe('application/vnd.openxmlformats-officedocument.presentationml.presentation');
262+
expect(getDocumentMimeType('data.xlsx')).toBe('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
263+
expect(getDocumentMimeType('data.csv')).toBe('text/csv');
264+
expect(getDocumentMimeType('unknown.xyz')).toBe('application/octet-stream');
265+
});
266+
267+
it('dispatches extraction based on file extension', async () => {
268+
const csvPath = path.join(tempDir, 'test.csv');
269+
fs.writeFileSync(csvPath, 'Name,Role\nAlice,Developer\nBob,Designer');
270+
const result = await extractDocument(csvPath);
271+
expect(result.success).toBe(true);
272+
expect(result.markdown).toContain('| Name | Role |');
273+
expect(result.markdown).toContain('| Alice | Developer |');
274+
});
275+
});
227276
});

0 commit comments

Comments
 (0)