openreader/tests/unit/pdf-stitch-cross-page-blocks.spec.ts
Richard R 37a90b734d feat(pdf): migrate to PP-DocLayoutV3 ONNX model and update PDF block taxonomy
Switch PDF layout parsing to use the PP-DocLayoutV3 ONNX model, replacing the previous Docling-based approach. Update all environment variables, model fetching, and manifest handling for the new model and its artifacts. Refactor block kind taxonomy throughout the codebase, tests, and UI to align with PP-DocLayoutV3 labels, including expanded and renamed block types. Revise document settings, block filtering, and stitching logic to support the new set of block kinds. Update documentation and environment variable references to reflect the model transition.

BREAKING CHANGE: PDF parsing now requires PP-DocLayoutV3 ONNX model and updated environment variables; block kind names and settings have changed throughout the system.
2026-05-18 04:26:39 -06:00

90 lines
2.6 KiB
TypeScript

import { expect, test } from '@playwright/test';
import { stitchCrossPageBlocks } from '../../src/lib/server/pdf-layout/stitchCrossPageBlocks';
import type { ParsedPdfBlock, ParsedPdfDocument, ParsedPdfBlockKind } from '../../src/types/parsed-pdf';
function makeBlock(
id: string,
kind: ParsedPdfBlockKind,
text: string,
page: number,
readingOrder: number,
): ParsedPdfBlock {
return {
id,
kind,
text,
fragments: [{
page,
bbox: [0, 0, 100, 10],
text,
readingOrder,
}],
};
}
function makeDoc(page1Blocks: ParsedPdfBlock[], page2Blocks: ParsedPdfBlock[]): ParsedPdfDocument {
return {
schemaVersion: 1,
documentId: 'doc',
parserVersion: 'test',
parsedAt: 0,
pages: [
{ pageNumber: 1, width: 100, height: 100, blocks: page1Blocks },
{ pageNumber: 2, width: 100, height: 100, blocks: page2Blocks },
],
};
}
test.describe('stitchCrossPageBlocks', () => {
test('stitches paragraph continuation across footer/header noise', () => {
const doc = makeDoc(
[
makeBlock('b1', 'text', 'This sentence continues', 1, 0),
makeBlock('b2', 'footer', 'Footer text', 1, 1),
],
[
makeBlock('b3', 'header', 'Header text', 2, 0),
makeBlock('b4', 'text', 'into the next page.', 2, 1),
],
);
const stitched = stitchCrossPageBlocks(doc);
const page1 = stitched.pages[0];
const page2 = stitched.pages[1];
expect(page1?.blocks[0]?.text).toBe('This sentence continues into the next page.');
expect(page1?.blocks[0]?.fragments).toHaveLength(2);
expect(page2?.blocks.map((b) => b.id)).toEqual(['b3']);
});
test('does not stitch across paragraph-title boundary', () => {
const doc = makeDoc(
[
makeBlock('b1', 'text', 'This sentence continues', 1, 0),
],
[
makeBlock('b2', 'paragraph_title', '2 New Section', 2, 0),
makeBlock('b3', 'text', 'into the next page.', 2, 1),
],
);
const stitched = stitchCrossPageBlocks(doc);
expect(stitched.pages[0]?.blocks[0]?.fragments).toHaveLength(1);
expect(stitched.pages[1]?.blocks.map((b) => b.id)).toEqual(['b2', 'b3']);
});
test('does not stitch when tail has sentence terminal', () => {
const doc = makeDoc(
[
makeBlock('b1', 'text', 'This sentence is complete.', 1, 0),
],
[
makeBlock('b2', 'text', 'next sentence starts here', 2, 0),
],
);
const stitched = stitchCrossPageBlocks(doc);
expect(stitched.pages[0]?.blocks[0]?.fragments).toHaveLength(1);
expect(stitched.pages[1]?.blocks.map((b) => b.id)).toEqual(['b2']);
});
});