extract-pdf 0.1.200 → 0.1.202
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -4
- package/dist/liteparse-wasm-to-html.d.ts +32 -0
- package/dist/pdf-to-html.cjs.js +1 -1
- package/dist/pdf-to-html.d.ts +8 -1
- package/dist/pdf-to-html.es.js +1 -1
- package/dist/utils/string-functions.d.ts +1 -0
- package/package.json +4 -5
- package/src/liteparse-to-html.ts +1 -4
- package/src/liteparse-wasm-to-html.ts +105 -0
- package/src/pdf-to-html.ts +19 -1
- package/src/utils/string-functions.ts +4 -0
package/README.md
CHANGED
|
@@ -58,8 +58,8 @@ const { html } = await convertPDFToHTML(buffer, { addPageNumbers: true });
|
|
|
58
58
|
| ----------------- | ---------------------- | ------------------------------------------------------------------------------------------ |
|
|
59
59
|
| `addPageNumbers` | `false` | Inserts `[n]` markers at each page boundary |
|
|
60
60
|
| `addCitation` | `true` | Reads PDF metadata and first-page heading to populate `title`/`author` in the return value |
|
|
61
|
-
| `method` | `"ts-block-algorithm"` | Parsing engine — `"ts-block-algorithm"` or `"liteparse"` (see below)
|
|
62
|
-
| `liteParseOptions`| `{}` | Passed through to LiteParse's constructor when `method
|
|
61
|
+
| `method` | `"ts-block-algorithm"` | Parsing engine — `"ts-block-algorithm"`, `"liteparse"`, or `"liteparse-wasm"` (see below) |
|
|
62
|
+
| `liteParseOptions`| `{}` | Passed through to LiteParse's constructor when `method` is `"liteparse"` or `"liteparse-wasm"` |
|
|
63
63
|
|
|
64
64
|
### Return value
|
|
65
65
|
|
|
@@ -69,17 +69,21 @@ const { html } = await convertPDFToHTML(buffer, { addPageNumbers: true });
|
|
|
69
69
|
|
|
70
70
|
## Parse methods
|
|
71
71
|
|
|
72
|
-
`convertPDFToHTML` supports
|
|
72
|
+
`convertPDFToHTML` supports three interchangeable parsing engines via `options.method`:
|
|
73
73
|
|
|
74
74
|
| Method | Engine | Environments | OCR |
|
|
75
75
|
| ------------------------------------ | -------------------------------------------------------------------- | ----------------------------------- | --- |
|
|
76
76
|
| `"ts-block-algorithm"` (default) | The pure-TS pipeline documented below (this package) | Node.js, Cloudflare Workers, browser | No |
|
|
77
77
|
| `"liteparse"` | [LiteParse](https://github.com/run-llama/liteparse) (native, `@llamaindex/liteparse`) | Node.js only | Optional |
|
|
78
|
+
| `"liteparse-wasm"` | [LiteParse](https://github.com/run-llama/liteparse) (WASM, `@llamaindex/liteparse-wasm`) | Node.js, Cloudflare Workers, browser | Optional (via callback) |
|
|
78
79
|
|
|
79
80
|
```ts
|
|
80
81
|
import { convertPDFToHTML } from "extract-pdf";
|
|
81
82
|
|
|
82
83
|
const { html } = await convertPDFToHTML(buffer, { method: "liteparse" });
|
|
84
|
+
|
|
85
|
+
// Or the WASM build, which also runs in browsers and Cloudflare Workers:
|
|
86
|
+
const { html } = await convertPDFToHTML(buffer, { method: "liteparse-wasm" });
|
|
83
87
|
```
|
|
84
88
|
|
|
85
89
|
LiteParse ships a native (napi) addon, so `method: "liteparse"` only runs in
|
|
@@ -88,7 +92,15 @@ it explicitly (`bun add @llamaindex/liteparse`) since it's an optional
|
|
|
88
92
|
dependency; if it isn't installed, `convertPDFToHTML` returns `{ error }`
|
|
89
93
|
instead of throwing.
|
|
90
94
|
|
|
91
|
-
|
|
95
|
+
`method: "liteparse-wasm"` delegates to LiteParse's WebAssembly build instead,
|
|
96
|
+
which runs anywhere WASM does — browsers, Cloudflare Workers, and Node.js.
|
|
97
|
+
Install it explicitly (`bun add @llamaindex/liteparse-wasm`) since it's also
|
|
98
|
+
an optional dependency; if it isn't installed, `convertPDFToHTML` returns
|
|
99
|
+
`{ error }` instead of throwing. The WASM build has no OCR engine built in —
|
|
100
|
+
pass a `liteParseOptions.ocrEngine` callback (e.g. backed by `tesseract-js`)
|
|
101
|
+
to enable OCR.
|
|
102
|
+
|
|
103
|
+
By default both LiteParse paths run with OCR disabled (`ocrEnabled: false`) —
|
|
92
104
|
matching this package's "instant, no backend" philosophy. Use
|
|
93
105
|
`detectPdfNeedsOcr` (below) to decide when a document is worth re-parsing with
|
|
94
106
|
`liteParseOptions: { ocrEnabled: true }`.
|
|
@@ -149,6 +161,8 @@ Raw pdfjs text spans
|
|
|
149
161
|
```
|
|
150
162
|
src/
|
|
151
163
|
pdf-to-html.ts — main entry point (convertPDFToHTML)
|
|
164
|
+
liteparse-to-html.ts — "liteparse" method (native napi addon)
|
|
165
|
+
liteparse-wasm-to-html.ts — "liteparse-wasm" method (WASM, browser/edge)
|
|
152
166
|
models/ — data classes: Page, ParseResult, TextItem,
|
|
153
167
|
│ LineItem, LineItemBlock, Word, BlockType, …
|
|
154
168
|
transforms/
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { LiteParseInit } from '@llamaindex/liteparse-wasm';
|
|
2
|
+
export interface LiteParseWasmHTMLOptions {
|
|
3
|
+
addPageNumbers?: boolean;
|
|
4
|
+
addCitation?: boolean;
|
|
5
|
+
liteParseOptions?: Partial<LiteParseInit>;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Converts a PDF (URL or ArrayBuffer) into HTML using LiteParse's WASM build,
|
|
9
|
+
* mirroring the return shape of `convertPDFToHTML`.
|
|
10
|
+
* @param pdfURLOrBuffer - URL to a PDF file or buffer from fs.readFile
|
|
11
|
+
* @param options.addPageNumbers default=false - Adds `[n]` markers at each page boundary
|
|
12
|
+
* @param options.addCitation default=true - Populates `title`/`author` from PDF metadata
|
|
13
|
+
* @param options.liteParseOptions - Passed through to the `LiteParse` constructor;
|
|
14
|
+
* defaults to `{ ocrEnabled: false, ocrFailureFatal: false }` (use detectPdfNeedsOcr
|
|
15
|
+
* to decide when a document is worth re-parsing with `ocrEnabled: true`, or pass
|
|
16
|
+
* `ocrEngine` to run OCR in-process, e.g. via tesseract-js)
|
|
17
|
+
* @returns `{ html, title, author, format: "pdf" }`, or `{ error }` on failure
|
|
18
|
+
* @category Extract
|
|
19
|
+
*/
|
|
20
|
+
export declare function convertPDFToHTMLWithLiteParseWasm(pdfURLOrBuffer: any, options?: LiteParseWasmHTMLOptions): Promise<{
|
|
21
|
+
error: any;
|
|
22
|
+
author?: undefined;
|
|
23
|
+
title?: undefined;
|
|
24
|
+
html?: undefined;
|
|
25
|
+
format?: undefined;
|
|
26
|
+
} | {
|
|
27
|
+
author: string;
|
|
28
|
+
title: string;
|
|
29
|
+
html: any;
|
|
30
|
+
format: string;
|
|
31
|
+
error?: undefined;
|
|
32
|
+
}>;
|
package/dist/pdf-to-html.cjs.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function t(t){for(;32===t.charCodeAt(0);)t=t.substring(1,t.length);return t}function e(t){for(;32===t.charCodeAt(t.length-1);)t=t.substring(0,t.length-1);return t}function s(t){return t>=48&&t<=57}function n(t){for(var e=0;e<t.length;e++)if(!s(t.charCodeAt(e)))return!1;return!0}function o(t,e){const s=e.charCodeAt(0);for(var n=0;n<t.length;n++)if(t.charCodeAt(n)!==s)return!1;return!0}function r(t){return function(t){const e=[];for(var s=0;s<t.length;s++)e.push(t.charCodeAt(s));return e}(t=t.toUpperCase()).filter(t=>32!==t&&9!==t&&46!==t)}function a(t){if(t.length>1)return!1;const e=t.charAt(0);return"-"===e||"•"===e||"–"===e}function i(t){return/^[\s]*[-•–][\s].*$/g.test(t)}function h(t,e){const s=new Set(t.toUpperCase().split(" ")),n=new Set(e.toUpperCase().split(" "));return new Set([...s].filter(t=>n.has(t))).size/Math.max(s.size,n.size)}var l=(t,e,s)=>Math.floor(t/e*s),c=(s,o,r)=>{for(const{str:a}of s){const s=e(t(a));n(s)&&(o[r]||(o[r]=[]),o[r].push(Number(s)))}return o},m=(t,e,s)=>{const n=l(1,6,s.length),o=l(5,6,s.length),r=c(s.slice(0,n),t,e);return c(s.slice(o),r,e)},u=t=>{let e=0;const s=Object.keys(t);if(0!==s.length&&1!==s.length)for(let n=0;n<s.length-1;n++){const o=t[s[n]],r=t[s[n+1]],a=e;for(let t=0;t<o.length&&e<2;t++)for(let a=0;a<r.length&&e<2;a++){const i=Number(s[n+1])-Number(s[n]);(o[t]+1===r[a]||i>1&&o[t]+i===r[a])&&e++}let i=n>0?Object.entries(t)[n-1]:Object.entries(t)[n];if(a===e)e=0,i=Object.entries(t)[n];else if(e>=2)return{pageIndex:Number(i[0]),pageNum:i[1][0]}}},p=(t,e)=>{const s={items:[...t.items]},n=l(1,6,s.items.length),o=l(5,6,s.items.length);return s.items=s.items.filter((t,r)=>{const a=r>0&&r<n,i=r>o&&r<s.items.length;return a||i?Number(t.str)!==Number(e):t}),s},f=class t{type;annotation;parsedElements;constructor(e){if(this.constructor===t)throw new TypeError("Can not construct abstract class.");this.type=e.type??null,this.annotation=e.annotation??null,this.parsedElements=e.parsedElements??null}},d=class extends f{x;y;width;height;text;font;lineFormat;unopenedFormat;unclosedFormat;constructor(t){super(t),this.x=t.x,this.y=t.y,this.width=t.width,this.height=t.height,this.text=t.text,this.font=t.font,this.lineFormat=t.lineFormat??null,this.unopenedFormat=t.unopenedFormat??null,this.unclosedFormat=t.unclosedFormat??null}},g=class{index;items;constructor(t){this.index=t.index,this.items=t.items||[]}};async function y(t,e={}){const s=e.timeout?1e3*e.timeout:1e4,n=new AbortController,o=setTimeout(()=>n.abort(),s);try{const s=await fetch(t,{signal:n.signal});if(clearTimeout(o),!s.ok)throw new Error(`HTTP ${s.status}`);return"arraybuffer"===e.responseType?await s.arrayBuffer():await s.text()}catch(r){throw clearTimeout(o),r}}var w=class t{name;itemType;constructor(e,s){if(this.constructor===t)throw new TypeError("Can not construct abstract class.");if(this.transform===t.prototype.transform)throw new TypeError("Please implement abstract method 'transform()'.");this.name=e,this.itemType=s}transform(t){throw new TypeError("Do not call abstract method foo from child.")}completeTransform(t){return t.messages=[],t}},x=class{category;color;constructor(t){this.category=t.category,this.color=t.color}},E=new x({category:"Added",color:"green"}),T=new x({category:"Removed",color:"red"}),v=new x({category:"Unchanged",color:"brown"}),b=new x({category:"Detected",color:"green"}),L=new x({category:"Modified",color:"green"}),O=class t extends w{constructor(e){if(super(e,d.name),this.constructor===t)throw new TypeError("Can not construct abstract class.")}completeTransform(t){return t.messages=[],t.pages.forEach(t=>{t.items=t.items.filter(t=>!t.annotation||t.annotation!==T),t.items.forEach(t=>t.annotation=null)}),t}},I=class{pages;globals;messages;constructor(t){this.pages=t.pages||[],this.globals=t.globals||{},this.messages=t.messages||[]}},S=class{string;type;format;constructor(t){this.string=t.string,this.type=t.type??null,this.format=t.format??null}},k=class extends f{x;y;width;height;words;constructor(t){super(t),this.x=t.x??0,this.y=t.y??0,this.width=t.width??0,this.height=t.height??0,this.words=t.words||[],t.text&&!t.words&&(this.words=t.text.split(" ").filter(t=>t.trim().length>0).map(t=>new S({string:t})))}text(){return this.wordStrings().join(" ")}wordStrings(){return this.words.map(t=>t.string)}},F=class t{results;stash;constructor(){if(this.constructor===t)throw new TypeError("Can not construct abstract class.");this.results=[],this.stash=[]}consumeAll(t){t.forEach(t=>this.consume(t))}consume(t){this.shouldStash(t)?(this.matchesStash(t)||this.flushStash(),this.pushOnStash(t)):(this.stash.length>0&&this.flushStash(),this.results.push(t))}pushOnStash(t){this.onPushOnStash(t),this.stash.push(t)}complete(){return this.stash.length>0&&this.flushStash(),this.results}matchesStash(t){if(0===this.stash.length)return!0;const e=this.stash[this.stash.length-1];return this.doMatchesStash(e,t)}flushStash(){this.stash.length>0&&(this.doFlushStash(this.stash,this.results),this.stash=[])}onPushOnStash(t){}shouldStash(t){throw new TypeError(" Do not call abstract method foo from child."+t)}doMatchesStash(t,e){throw new TypeError(" Do not call abstract method foo from child."+t+e)}doFlushStash(t,e){throw new TypeError(" Do not call abstract method foo from child."+t+e)}},C=class{footnoteLinks;footnotes;containLinks;formattedWords;constructor(t){this.footnoteLinks=t.footnoteLinks||[],this.footnotes=t.footnotes||[],this.containLinks=t.containLinks??!1,this.formattedWords=t.formattedWords??0}add(t){this.footnoteLinks=this.footnoteLinks.concat(t.footnoteLinks),this.footnotes=this.footnotes.concat(t.footnotes),this.containLinks=this.containLinks||t.containLinks,this.formattedWords+=t.formattedWords}};function N(t){t.sort((t,e)=>t.x-e.x)}var M={BOLD:{name:"BOLD",startSymbol:"<strong>",endSymbol:"</strong>"},OBLIQUE:{name:"OBLIQUE",startSymbol:"<em>",endSymbol:"</em>"},BOLD_OBLIQUE:{name:"BOLD_OBLIQUE",startSymbol:"<strong><em>",endSymbol:"</em></strong>"}},D={LINK:{name:"LINK",toText:t=>`<a href="${t}">${t}</a>`},FOOTNOTE_LINK:{name:"FOOTNOTE_LINK",attachWithoutWhitespace:!0,plainTextFormat:!0,toText:t=>`<sup><a href="#${t}">${t}</a></sup>`},FOOTNOTE:{name:"FOOTNOTE",toText:t=>`<p id="${t}">^${t}</p>`}},H=class{fontToFormats;constructor(t){this.fontToFormats=t}compact(t){N(t);const e=new B(this.fontToFormats);e.consumeAll(t.map(t=>new d({...t})));const s=e.complete();var n=0,o=0;return t.forEach(t=>{n=Math.max(n,t.height),o+=t.width}),new k({x:t[0].x,y:t[0].y,height:n,width:o,words:s,parsedElements:new C({footnoteLinks:e.footnoteLinks,footnotes:e.footnotes,containLinks:e.containLinks,formattedWords:e.formattedWords})})}},B=class extends F{fontToFormats;footnoteLinks;footnotes;formattedWords;containLinks;stashedNumber;firstY;currentItem;constructor(t){super(),this.fontToFormats=t,this.footnoteLinks=[],this.footnotes=[],this.formattedWords=0,this.containLinks=!1,this.stashedNumber=!1,this.currentItem=null}shouldStash(t){return this.firstY||(this.firstY=t.y),this.currentItem=t,!0}onPushOnStash(t){this.stashedNumber=n(t.text.trim())}doMatchesStash(t,e){if(this.fontToFormats.get(t.font)!==this.fontToFormats.get(e.font))return!1;const s=n(e.text.trim());return this.stashedNumber===s}doFlushStash(t,e){if(this.stashedNumber){const s=t.map(t=>t.text).join("").trim();t[0].y>this.firstY?(e.push(new S({string:`${s}`,type:D.FOOTNOTE_LINK})),this.footnoteLinks.push(parseInt(s))):this.currentItem&&this.currentItem.y<t[0].y?(e.push(new S({string:`${s}`,type:D.FOOTNOTE})),this.footnotes.push(s)):this.copyStashItemsAsText(t,e)}else this.copyStashItemsAsText(t,e)}copyStashItemsAsText(t,e){const s=this.fontToFormats.get(t[0].font);e.push(...this.itemsToWords(t,s))}itemsToWords(t,e){const s=(n=t,o="",r=null,n.forEach(t=>{var e=t.text;o.endsWith(" ")||e.startsWith(" ")||(r?t.x-r.x-r.width>5&&(o+=" "):a(t.text)&&(e+=" ")),o+=e,r=t}),o).split(" ");var n,o,r;const i=e?M[e]:null;return s.filter(t=>t.trim().length>0).map(t=>{var e=null;return t.startsWith("http:")?(this.containLinks=!0,e=D.LINK):t.startsWith("www.")&&(this.containLinks=!0,t=`http://${t}`,e=D.LINK),i&&this.formattedWords++,new S({string:t,type:e,format:i})})}};var U=class extends O{fontMap;constructor(t){super("Calculate Global Stats"),this.fontMap=t}transform(t){const e={},s={};var n,o=0;t.pages.forEach(t=>{t.items.forEach(t=>{t.height&&(e[t.height]=e[t.height]?e[t.height]+1:1,s[t.font]=s[t.font]?s[t.font]+1:1,t.height>o&&(o=t.height,n=t.font))})});const r=parseInt(A(e)),a=A(s),i={};t.pages.forEach(t=>{var e;t.items.forEach(t=>{if(t.height===r&&t.text.trim().length>0){if(e&&t.y!==e.y){const s=e.y-t.y;s>0&&(i[s]=i[s]?i[s]+1:1)}e=t}else e=null})});const h=parseInt(A(i)),l=[],c=new Map;this.fontMap?.forEach(function(t,e){l.push(e+" = "+t.name);const s=t.name.toLowerCase();var o=null;e===a?o=null:s.includes("bold")&&(s.includes("oblique")||s.includes("italic"))?o=M.BOLD_OBLIQUE:s.includes("bold")?o=M.BOLD:s.includes("oblique")||s.includes("italic")?o=M.OBLIQUE:s===n&&(o=M.BOLD),o&&c.set(e,o.name)}),l.sort();const m=t.pages.map(t=>({...t,items:t.items.map(t=>({...t}))}));return new I({...t,pages:m,globals:{mostUsedHeight:r,mostUsedFont:a,mostUsedDistance:h,maxHeight:o,maxHeightFont:n,fontToFormats:c},messages:["Items per height: "+JSON.stringify(e),"Items per font: "+JSON.stringify(s),"Items per distance: "+JSON.stringify(i),"Fonts:"+JSON.stringify(l)]})}};function A(t){var e=0,s="";return Object.keys(t).map(n=>{(!s||t[n]>e)&&(e=t[n],s=n)}),s}var P=class t extends w{constructor(e){if(super(e,k.name),this.constructor===t)throw new TypeError("Can not construct abstract class.")}completeTransform(t){return t.messages=[],t.pages.forEach(t=>{t.items=t.items.filter(t=>!t.annotation||t.annotation!==T),t.items.forEach(t=>t.annotation=null)}),t}},W=class{mostUsedDistance;constructor(t){this.mostUsedDistance=t.mostUsedDistance||12}group(t){const e=[];var s=[];return t.forEach(t=>{s.length>0&&Math.abs(s[0].y-t.y)>=this.mostUsedDistance/2&&(e.push(s),s=[]),s.push(t)}),e.push(s),e.forEach(t=>{N(t)}),e}},$={H1:{name:"H1",headline:!0,headlineLevel:1,toText:t=>"<h1>"+j(t.items,!0)+"</h1>"},H2:{name:"H2",headline:!0,headlineLevel:2,toText:t=>"<h2>"+j(t.items,!0)+"</h2>"},H3:{name:"H3",headline:!0,headlineLevel:3,toText:t=>"<h3>"+j(t.items,!0)+"</h3>"},H4:{name:"H4",headline:!0,headlineLevel:4,toText:t=>"<h4>"+j(t.items,!0)+"</h4>"},H5:{name:"H5",headline:!0,headlineLevel:5,toText:t=>"<h5>"+j(t.items,!0)+"</h5>"},H6:{name:"H6",headline:!0,headlineLevel:6,toText:t=>"<h6>"+j(t.items,!0)+"</h6>"},TOC:{name:"TOC",mergeToBlock:!0,toText:t=>j(t.items,!0)},FOOTNOTES:{name:"FOOTNOTES",mergeToBlock:!0,mergeFollowingNonTypedItems:!0,toText:t=>"<p>"+j(t.items,!1)+"</p>"},CODE:{name:"CODE",mergeToBlock:!0,toText:t=>"<code>"+j(t.items,!0)+"</code>"},LIST:{name:"LIST",mergeToBlock:!1,mergeFollowingNonTypedItemsWithSmallDistance:!0,toText:t=>"<ul>\n"+j(t.items,!1)+"</ul>"},PARAGRAPH:{name:"PARAGRAPH",toText:t=>"<p>"+j(t.items,!1)+"</p>"}};function j(t,e){var s,n="";const o=()=>{n+=s.endSymbol,s=null};return t.forEach((r,a)=>{var i;r&&(r.words.forEach((t,r)=>{const a=t.type,i=t.format;var h;!s||i&&i===s||o(),r>0&&(!a||!a.attachWithoutWhitespace)&&(1!==(h=t.string).length||"."!==h[0]&&"!"!==h[0]&&"?"!==h[0])&&(n+=" "),!i||s||e||(n+=(s=i).startSymbol),!a||e&&!a.plainTextFormat?n+=t.string:n+=a.toText(t.string)}),!s||a!==t.length-1&&(0===(i=t[a+1]).words.length?null:i.words[0].format)===s||o(),n+="\n")}),n}$.enumValueOf=function(t){return $[t]},$.isHeadline=function(t){return t&&2===t.name.length&&"H"===t.name[0]},$.blockToText=function(t){return t.type?t.type.toText(t):j(t.items,!1)},$.headlineByLevel=function(t){return 1===t?$.H1:2===t?$.H2:3===t?$.H3:4===t?$.H4:5===t?$.H5:(t>6&&console.warn("Unsupported headline level: "+t+" (supported are 1-6), defaulting to level 6"),$.H6)};var q=class extends P{constructor(){super("Compact To Lines")}transform(t){const{mostUsedDistance:e,fontToFormats:s}=t.globals,n=[],o=[];var r=0,a=0;const i=new W({mostUsedDistance:e}),h=new H(s);return t.pages.forEach(t=>{if(t.items.length>0){const e=[];i.group(t.items).forEach(s=>{const i=h.compact(s);if(s.length>1&&(i.annotation=E,s.forEach(t=>{t.annotation=T,e.push(new k({...t}))})),0===i.words.length&&(i.annotation=T),e.push(i),i.parsedElements.formattedWords&&(a+=i.parsedElements.formattedWords),i.parsedElements.containLinks&&r++,i.parsedElements.footnoteLinks.length>0){const e=i.parsedElements.footnoteLinks.map(e=>({footnoteLink:e,page:t.index+1}));o.push.apply(o,e)}if(i.parsedElements.footnotes.length>0){i.type=$.FOOTNOTES;const e=i.parsedElements.footnotes.map(e=>({footnote:e,page:t.index+1}));n.push.apply(n,e)}}),t.items=e}}),new I({...t,messages:["Detected "+a+" formatted words","Found "+r+" links","Detected "+o.length+" footnotes links","Detected "+n.length+" footnotes"]})}};function Y(t){var e=0;if(0===t.trim().length)return e;for(var n=0;n<t.length;n++){const o=t.charCodeAt(n);s(o)||32===o||160===o||(e=(e<<5)-e+o,e|=0)}return e}var R=class extends P{constructor(){super("Remove Repetitive Elements")}transform(t){const e=[],s={},n={};t.pages.forEach(t=>{const o=t.items.reduce((t,e)=>(e.y<t.minY?(t.minElements=[e],t.minY=e.y):e.y===t.minY&&t.minElements.push(e),e.y>t.maxY?(t.maxElements=[e],t.maxY=e.y):e.y===t.maxY&&t.maxElements.push(e),t),{minY:999,maxY:0,minElements:[],maxElements:[]}),r=Y(o.minElements.reduce((t,e)=>t+e.text().toUpperCase(),"")),a=Y(o.maxElements.reduce((t,e)=>t+e.text().toUpperCase(),""));e.push({minElements:o.minElements,maxElements:o.maxElements,minLineHash:r,maxLineHash:a}),s[r]=s[r]?s[r]+1:1,n[a]=n[a]?n[a]+1:1});var o=0,r=0;return t.pages.forEach((a,i)=>{s[e[i].minLineHash]>=Math.max(3,2*t.pages.length/3)&&(e[i].minElements.forEach(t=>{t.annotation=T}),r++),n[e[i].maxLineHash]>=Math.max(3,2*t.pages.length/3)&&(e[i].maxElements.forEach(t=>{t.annotation=T}),o++)}),new I({...t,messages:["Removed Header: "+o,"Removed Footers: "+r]})}},V=class extends P{constructor(){super("Vertical to Horizontal Text")}transform(t){var e=0;return t.pages.forEach(t=>{const s=new K;s.consumeAll(t.items),t.items=s.complete(),e+=s.foundVerticals}),new I({...t,messages:["Converted "+e+" verticals"]})}},K=class extends F{foundVerticals;constructor(){super(),this.foundVerticals=0}shouldStash(t){return 1===t.words.length&&1===t.words[0].string.length}doMatchesStash(t,e){return t.y-e.y>5&&t.words[0].type===e.words[0].type}doFlushStash(t,e){if(t.length>5){var s=[],n=999,o=0,r=0,a=0;t.forEach(t=>{t.annotation=T,e.push(t),s.push(t.words[0]),n=Math.min(n,t.x),o=Math.max(o,t.y),r+=t.width,a=Math.max(a,t.height)}),e.push(new k({...t[0],x:n,y:o,width:r,height:a,words:s,annotation:E})),this.foundVerticals++}else e.push(...t)}},J=class{headlineCharCodes;stackedLineItems;stackedChars;constructor(t){this.headlineCharCodes=r(t.headline),this.stackedLineItems=[],this.stackedChars=0}consume(t){const e=r(t.text());if(this.matchAll(e)){if(this.stackedLineItems.push(t),this.stackedChars+=e.length,this.stackedChars===this.headlineCharCodes.length)return this.stackedLineItems}else this.stackedChars>0&&(this.stackedChars=0,this.stackedLineItems=[],this.consume(t));return null}matchAll(t){for(var e=0;e<t.length;e++){const s=this.headlineCharCodes[this.stackedChars+e];if(t[e]!==s)return!1}return!0}},Q=class extends P{constructor(){super("Detect TOC")}transform(t){const e=[],r=Math.min(20,t.pages.length),a=new G;var i,l,c=[];t.pages.slice(0,r).forEach(t=>{var r=0;const h=new Set,m=[];var u,p;if(t.items.filter(t=>t.words.includes(t=>o(t.string,"."))).forEach(t=>{var e=t.words.filter(t=>!o(t.string,"."));const a=[];for(;e.length>0&&n(e[e.length-1].string);){const t=e.pop();a.unshift(t.string)}if(0===a.length&&e.length>0){const t=e[e.length-1];for(;s(t.string.charCodeAt(t.string.length-1));)a.unshift(t.string.charAt(t.string.length-1)),t.string=t.string.substring(0,t.string.length-1)}var i=a.length>0;i?(i=!0,u&&(e.push(...u),u=null),m.push(new X({pageNumber:parseInt(a.join("")),lineItem:new k({...t,words:e})})),r++):l?(u&&h.add(p),u=e,p=t):l=t}),100*r/t.items.length>75){e.push(t.index+1),i=t,a.levelPageItems(m),c.push(...m);const s=[];t.items.forEach(t=>{h.has(t)||(t.annotation=T),s.push(t),t===l&&s.push(new k({...t,type:$.H2,annotation:E}))}),t.items=s}else l=null});var m=c.length;const u=[],p=[],f={};if(e.length>0){c.forEach(t=>{i.items.push(new k({words:[new S({string:" ".repeat(3*t.level)+"-"})].concat(t.lineItem.words),type:$.TOC,annotation:E}))});const e=function(t,e){for(var s of e){const e=_(t,s.lineItem.text());if(e)return e.index-s.pageNumber}return null}(t.pages.filter(t=>t.index>i.index),c);c.forEach(s=>{var n,o=t.pages[s.pageNumber+e];o&&((n=z(o,s.lineItem.text()))||(o=t.pages[s.pageNumber+e+1])&&(n=z(o,s.lineItem.text()))),n?function(t,e,s,n){s.headlineItems.forEach(t=>t.annotation=T);const o=$.headlineByLevel(e.level+2),r=s.headlineItems.reduce((t,e)=>Math.max(t,e.height),0);t.items.splice(s.lineIndex+1,0,new k({...s.headlineItems[0],words:e.lineItem.words,height:r,type:o,annotation:E}));var a=n[o.name];a?(a.min=Math.min(a.min,r),a.max=Math.max(a.max,r)):(a={min:r,max:r},n[o.name]=a)}(o,s,n,f):u.push(s)});var d=i.index+2,g=[];const s=e=>{g.length>0&&(g.forEach(s=>{const n=$.headlineByLevel(s.level+2),o=f[n.name];if(o){const[r,a]=function(t,e,s,n,o){const r=e.lineItem.text().toUpperCase();for(var a=n;a<=o;a++){const e=t[a-1];if(e){const t=e.items.findIndex(t=>!t.type&&!t.annotation&&t.height>=s.min&&t.height<=s.max&&h(r,t.text())>=.5);if(t>-1)return[a-1,t]}}return[-1,-1]}(t.pages,s,o,d,e);if(a>-1){const e=t.pages[r];e.items[a].annotation=T,e.items.splice(a+1,0,new k({...s.lineItem,type:n,annotation:E})),p.push(s)}}}),g=[])};u.length>0&&(c.forEach(t=>{u.includes(t)?g.push(t):(s(t.pageNumber),d=t.pageNumber)}),g.length>0&&s(t.pages.length))}const y=[];return y.push("Detected "+e.length+" table of content pages"),e.length>0&&(y.push("TOC headline heights: "+JSON.stringify(f)),y.push("Found TOC headlines: "+(m-u.length+p.length)+"/"+m)),u.length>0&&(y.push("Found TOC headlines (by size): "+p.map(t=>t.lineItem.text())),y.push("Missing TOC headlines: "+u.filter(t=>!p.includes(t)).map(t=>t.lineItem.text()+"=>"+t.pageNumber))),new I({...t,globals:{...t.globals,tocPages:e,headlineTypeToHeightRange:f},messages:y})}};function _(t,e){for(var s of t)if(z(s,e))return s;return null}function z(t,e){const s=new J({headline:e});var n=0;for(var o of t.items){const t=s.consume(o);if(t)return{lineIndex:n,headlineItems:t};n++}return null}var G=class{levelByMethod;uniqueFonts;constructor(){this.levelByMethod=null,this.uniqueFonts=[]}levelPageItems(t){if(!this.levelByMethod)if(this.calculateUniqueX(t).length>1)this.levelByMethod=this.levelByXDiff;else{const e=this.calculateUniqueFonts(t);e.length>1?(this.uniqueFonts=e,this.levelByMethod=this.levelByFont):this.levelByMethod=this.levelToZero}this.levelByMethod(t)}levelByXDiff(t){const e=this.calculateUniqueX(t);t.forEach(t=>{t.level=e.indexOf(t.lineItem.x)})}levelByFont(t){t.forEach(t=>{t.level=this.uniqueFonts.indexOf(t.lineItem.font)})}levelToZero(t){t.forEach(t=>{t.level=0})}calculateUniqueX(t){var e=t.reduce(function(t,e){return t.indexOf(e.lineItem.x)<0&&t.push(e.lineItem.x),t},[]);return e.sort((t,e)=>t-e),e}calculateUniqueFonts(t){return t.reduce(function(t,e){return t.indexOf(e.lineItem.font)<0&&t.push(e.lineItem.font),t},[])}},X=class{lineItem;pageNumber;level;constructor(t){this.lineItem=t.lineItem,this.pageNumber=t.pageNumber,this.level=0}},Z=class extends P{constructor(){super("Detect List Items")}transform(t){var e=0,s=0;return t.pages.forEach(t=>{const n=[];t.items.forEach(t=>{if(n.push(t),!t.type){var o=t.text();if(a(t.words[0].string))if(e++,"-"===t.words[0].string)t.annotation=b,t.type=$.LIST;else{t.annotation=T;const e=t.words.map(t=>new S({...t}));e[0].string="-",n.push(new k({...t,words:e,annotation:E,type:$.LIST}))}else/^[\s]*[\d]*[.][\s].*$/g.test(o)&&(s++,t.annotation=b,t.type=$.LIST)}}),t.items=n}),new I({...t,messages:["Detected "+e+" plain list items.","Detected "+s+" numbered list items."]})}},tt=class extends P{constructor(){super("Detect Headers")}transform(t){const{tocPages:e,headlineTypeToHeightRange:s,mostUsedHeight:n,mostUsedDistance:o,mostUsedFont:r,maxHeight:a}=t.globals,h=e.length>0;var l=0;const c=function(t,e){const s=new Set;return t.forEach(t=>{t.items.forEach(n=>{n.type||n.height!==e||s.add(t)})}),s}(t.pages,a),m=n+(a-n)/4;if(c.forEach(t=>{t.items.forEach(t=>{const e=t.height;!t.type&&e>m&&(t.type=e===a?$.H1:$.H2,t.annotation=b,l++)})}),h)Object.keys(s).forEach(e=>{var o=s[e];o.max>n&&t.pages.forEach(t=>{t.items.forEach(t=>{t.type||t.height!==o.max||(t.annotation=b,t.type=$.enumValueOf(e),l++)})})});else{const e=[];t.pages.forEach(t=>{t.items.forEach(t=>{!t.type&&t.height>n&&!i(t.text())&&(e.includes(t.height)||e.push(t.height))})}),e.sort((t,e)=>e-t),e.forEach((e,s)=>{if(s+2<=6){const n=$.headlineByLevel(2+s);t.pages.forEach(t=>{t.items.forEach(t=>{t.type||t.height!==e||i(t.text())||(l++,t.annotation=b,t.type=n)})})}})}var u=1;if(t.pages.forEach(t=>{t.items.forEach(t=>{t.type&&t.type.headline&&(u=Math.max(u,t.type.headlineLevel))})}),u<6){const e=$.headlineByLevel(u+1);t.pages.forEach(t=>{var s;t.items.forEach(t=>{!t.type&&t.height===n&&t.font!==r&&(!s||s.y<t.y||s.type&&s.type.headline||s.y-t.y>2*o)&&t.text()===t.text().toUpperCase()&&(l++,t.annotation=b,t.type=e),s=t})})}return new I({...t,messages:["Detected "+l+" headlines."]})}};var et=class extends f{items;constructor(t){super(t),this.items=[],t.items&&t.items.forEach(t=>this.addItem(t))}addItem(t){if(this.type&&t.type&&this.type!==t.type)throw new Error(`Adding item of type ${t.type.name} to block of type ${this.type.name}`);this.type||(this.type=t.type),t.parsedElements&&(this.parsedElements?this.parsedElements.add(t.parsedElements):this.parsedElements=t.parsedElements);const e=new k({...t});e.type=null,this.items.push(e)}},st=class t extends w{constructor(e){if(super(e,et.name),this.constructor===t)throw new TypeError("Can not construct abstract class.")}completeTransform(t){return t.messages=[],t.pages.forEach(t=>{t.items=t.items.filter(t=>!t.annotation||t.annotation!==T),t.items.forEach(t=>t.annotation=null)}),t}},nt=class extends st{constructor(){super("Gather Blocks")}transform(t){const{mostUsedDistance:e}=t.globals;var s=0,n=0;return t.pages.map(t=>{n+=t.items.length;const o=[];var r=new et({});const a=()=>{r.items.length>1&&(r.annotation=b),o.push(r),r=new et({}),s++};var i=function(t){var e=999;return t.forEach(t=>{e=Math.min(e,t.x)}),999===e?null:e}(t.items);t.items.forEach(t=>{r.items.length>0&&function(t,e,s,n){if(t.type&&t.type.mergeFollowingNonTypedItems&&!e.type)return!1;const o=t.items[t.items.length-1],r=function(t,e,s,n){const o=t.y-e.y;if(o<0-n/2)return!0;var r=n+1;t.x>s&&e.x>s&&(r=n+n/2);return o>r}(o,e,s,n);if(t.type&&t.type.mergeFollowingNonTypedItemsWithSmallDistance&&!e.type&&!r)return!1;if(e.type!==t.type)return!0;return e.type?!e.type.mergeToBlock:r}(r,t,i,e)&&a(),r.addItem(t)}),r.items.length>0&&a(),t.items=o}),new I({...t,messages:["Gathered "+s+" blocks out of "+n+" line items"]})}};var ot=class extends st{constructor(){super("$1")}transform(t){const e=t.globals.mostUsedHeight??0;var s=0;return t.pages.forEach(t=>{var n=function(t){var e=999;return t.forEach(t=>{t.items.forEach(t=>{e=Math.min(e,t.x)})}),999===e?null:e}(t.items);t.items.forEach(t=>{!t.type&&function(t,e,s){if(0===e.length)return!1;if(1===e.length)return e[0].x>t&&e[0].height<=s+1;for(var n of e)if(n.x===t)return!1;return!0}(n,t.items,e)&&(t.annotation=b,t.type=$.CODE,s++)})}),new I({...t,messages:["Detected "+s+" code/quote items."]})}};var rt=class extends st{constructor(){super("Level Lists")}transform(t){var e=0,s=0;return t.pages.forEach(t=>{t.items.filter(t=>t.type===$.LIST).forEach(t=>{var n,o=0;const r={};var a=!1;t.items.forEach(t=>{n?t.x>n?(o++,r[t.x]=o):t.x<n&&(o=r[t.x]):r[t.x]=0,o>0&&(t.words=[new S({string:" ".repeat(3*o)})].concat(t.words),a=!0),n=t.x}),e++,a?(s++,t.annotation=L):t.annotation=v})}),new I({...t,messages:["Modified "+s+" / "+e+" list blocks."]})}},at=class extends w{constructor(){super("To Text Blocks","TextBlock")}transform(t){return t.pages.forEach(t=>{const e=[];t.items.forEach(t=>{const s=t.type?t.type.name:"Unknown";e.push({category:s,text:$.blockToText(t)})}),t.items=e}),new I({...t})}},it=class extends w{constructor(){super("To HTML","String")}transform(t){return t.pages.forEach(t=>{var e="";t.items.forEach(t=>{let s;s="TOC"===t.category?t.text:t.text.replace(/(\r\n|\n|\r)/gm,"\n"),"LIST"!==t.category&&(s=s.split("- ").join("")),"CODE"===t.category&&(s=s.split("<code>").join("").split("</code>").join("")),e+=`<p>${s}</p>\n\n`}),t.items=[e]}),new I({...t})}};async function ht(t,e={}){const{addPageNumbers:s=!1,addCitation:n=!0,liteParseOptions:o={}}=e,r="string"==typeof t?await y(t,{responseType:"arraybuffer",timeout:10}):t;let a;try{({LiteParse:a}=await(import("@llamaindex/liteparse")))}catch(u){return{error:`method: 'liteparse' requires the optional @llamaindex/liteparse dependency (Node.js only): ${u.message}`}}const i=new a({quiet:!0,ocrEnabled:!1,ocrFailureFatal:!1,...o});let h;try{h=await i.parse(new Uint8Array(r))}catch(u){return{error:u.message}}const l=h.pages.reduce((t,e)=>{const n=e.text.split(/\n{2,}/).filter(t=>t.trim().length>0).map(t=>{return(e=t,e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")).replace(/\n/g,"<br/>");var e}).join("</p><p>");return t+`<p id="page-${e.pageNum}">${s?` [${e.pageNum}] `:""}${n}</p>`},"");let c,m;return n&&(m=h.creator||h.producer,c=h.pages[0]?.text.split("\n").find(t=>t.trim().length>0)),{author:m,title:c,html:l,format:"pdf"}}exports.convertPDFToHTML=async function(t,e={}){if("liteparse"===e.method){const{method:s,...n}=e;return ht(t,n)}var{addPageNumbers:s=!1,addCitation:n=!0}=e,o="string"==typeof t?await y(t,{responseType:"arraybuffer",timeout:10}):t;let r;try{let{resolvePDFJS:t}=await(import("https://cdn.jsdelivr.net/npm/pdfjs-serverless@1.1.0/+esm"));const{getDocument:e}=await t();r=await e({data:new Uint8Array(o),useSystemFonts:!0,verbosity:0}).promise}catch(T){return{error:T.message}}const a=[...Array(r.numPages).keys()].map(t=>new g({index:t}));let i,h={};for(let p=1;p<=r.numPages;p++){const t=await r.getPage(p),e=await t.getTextContent();if(!(Object.keys(h).length<10)){i=u(h);break}h=m(h,t.pageNumber-1,e.items)}let l=i?i.pageNum:0;for(let m=1;m<=r.numPages;m++){const t=await r.getPage(m);await t.getOperatorList();const e=t.getViewport({scale:1});let s=await t.getTextContent();i&&t.pageIndex>=i.pageIndex&&(s=p(s,l),l++);const n=s.items.map(t=>{const s=[1,0,0,1,0,0];for(let r=0;r<6;r++)s[r]+=t.transform[r]*e.transform[r%2?3:0],r%2&&(s[r+1]+=t.transform[r]*e.transform[1]);const n=Math.sqrt(s[2]*s[2]+s[3]*s[3]),o=t.height/n;return new d({x:Math.round(t.transform[4]),y:Math.round(t.transform[5]),width:Math.round(t.width),height:Math.round(o<=1?t.height:o),text:t.str,font:t.fontName})});a[t.pageNumber-1].items=n}var c=new I({pages:a});let f;[new U,new q,new R,new V,new Q,new tt,new Z,new nt,new ot,new rt,new at,new it].forEach(t=>{f&&(c=f.completeTransform(c)),c=t.transform(c),f=t});var w=c.pages.reduce((t,e,n)=>t+`<p id="page-${n+1}">${s?` [${n+1}] `:""}${e.items.join('</p><p id="page-'+n+'">')}</p>`,"");if(n){var{Author:x,Title:E}=(await r.getMetadata()).info;E=w.slice(0,400).match(/<h[0-9]>(.*?)<\/h[0-9]>/)?.[1]||E}return{author:x,title:E,html:w,format:"pdf"}},exports.convertPDFToHTMLWithLiteParse=ht,exports.detectPdfNeedsOcr=async function(t,e={}){const s="string"==typeof t?await y(t,{responseType:"arraybuffer",timeout:10}):t,{LiteParse:n}=await(import("@llamaindex/liteparse")),o=await new n({quiet:!0,...e.liteParseOptions}).isComplex(new Uint8Array(s));return{needsOcr:o.some(t=>t.needsOcr),pages:o,reasons:[...new Set(o.flatMap(t=>t.reasons))]}};
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function t(t){for(;32===t.charCodeAt(0);)t=t.substring(1,t.length);return t}function e(t){for(;32===t.charCodeAt(t.length-1);)t=t.substring(0,t.length-1);return t}function s(t){return t>=48&&t<=57}function n(t){for(var e=0;e<t.length;e++)if(!s(t.charCodeAt(e)))return!1;return!0}function o(t,e){const s=e.charCodeAt(0);for(var n=0;n<t.length;n++)if(t.charCodeAt(n)!==s)return!1;return!0}function r(t){return function(t){const e=[];for(var s=0;s<t.length;s++)e.push(t.charCodeAt(s));return e}(t=t.toUpperCase()).filter(t=>32!==t&&9!==t&&46!==t)}function a(t){if(t.length>1)return!1;const e=t.charAt(0);return"-"===e||"•"===e||"–"===e}function i(t){return/^[\s]*[-•–][\s].*$/g.test(t)}function h(t){return t.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}function l(t,e){const s=new Set(t.toUpperCase().split(" ")),n=new Set(e.toUpperCase().split(" "));return new Set([...s].filter(t=>n.has(t))).size/Math.max(s.size,n.size)}var c=(t,e,s)=>Math.floor(t/e*s),m=(s,o,r)=>{for(const{str:a}of s){const s=e(t(a));n(s)&&(o[r]||(o[r]=[]),o[r].push(Number(s)))}return o},u=(t,e,s)=>{const n=c(1,6,s.length),o=c(5,6,s.length),r=m(s.slice(0,n),t,e);return m(s.slice(o),r,e)},p=t=>{let e=0;const s=Object.keys(t);if(0!==s.length&&1!==s.length)for(let n=0;n<s.length-1;n++){const o=t[s[n]],r=t[s[n+1]],a=e;for(let t=0;t<o.length&&e<2;t++)for(let a=0;a<r.length&&e<2;a++){const i=Number(s[n+1])-Number(s[n]);(o[t]+1===r[a]||i>1&&o[t]+i===r[a])&&e++}let i=n>0?Object.entries(t)[n-1]:Object.entries(t)[n];if(a===e)e=0,i=Object.entries(t)[n];else if(e>=2)return{pageIndex:Number(i[0]),pageNum:i[1][0]}}},d=(t,e)=>{const s={items:[...t.items]},n=c(1,6,s.items.length),o=c(5,6,s.items.length);return s.items=s.items.filter((t,r)=>{const a=r>0&&r<n,i=r>o&&r<s.items.length;return a||i?Number(t.str)!==Number(e):t}),s},f=class t{type;annotation;parsedElements;constructor(e){if(this.constructor===t)throw new TypeError("Can not construct abstract class.");this.type=e.type??null,this.annotation=e.annotation??null,this.parsedElements=e.parsedElements??null}},g=class extends f{x;y;width;height;text;font;lineFormat;unopenedFormat;unclosedFormat;constructor(t){super(t),this.x=t.x,this.y=t.y,this.width=t.width,this.height=t.height,this.text=t.text,this.font=t.font,this.lineFormat=t.lineFormat??null,this.unopenedFormat=t.unopenedFormat??null,this.unclosedFormat=t.unclosedFormat??null}},y=class{index;items;constructor(t){this.index=t.index,this.items=t.items||[]}};async function w(t,e={}){const s=e.timeout?1e3*e.timeout:1e4,n=new AbortController,o=setTimeout(()=>n.abort(),s);try{const s=await fetch(t,{signal:n.signal});if(clearTimeout(o),!s.ok)throw new Error(`HTTP ${s.status}`);return"arraybuffer"===e.responseType?await s.arrayBuffer():await s.text()}catch(r){throw clearTimeout(o),r}}var x=class t{name;itemType;constructor(e,s){if(this.constructor===t)throw new TypeError("Can not construct abstract class.");if(this.transform===t.prototype.transform)throw new TypeError("Please implement abstract method 'transform()'.");this.name=e,this.itemType=s}transform(t){throw new TypeError("Do not call abstract method foo from child.")}completeTransform(t){return t.messages=[],t}},E=class{category;color;constructor(t){this.category=t.category,this.color=t.color}},T=new E({category:"Added",color:"green"}),v=new E({category:"Removed",color:"red"}),b=new E({category:"Unchanged",color:"brown"}),L=new E({category:"Detected",color:"green"}),O=new E({category:"Modified",color:"green"}),I=class t extends x{constructor(e){if(super(e,g.name),this.constructor===t)throw new TypeError("Can not construct abstract class.")}completeTransform(t){return t.messages=[],t.pages.forEach(t=>{t.items=t.items.filter(t=>!t.annotation||t.annotation!==v),t.items.forEach(t=>t.annotation=null)}),t}},S=class{pages;globals;messages;constructor(t){this.pages=t.pages||[],this.globals=t.globals||{},this.messages=t.messages||[]}},F=class{string;type;format;constructor(t){this.string=t.string,this.type=t.type??null,this.format=t.format??null}},k=class extends f{x;y;width;height;words;constructor(t){super(t),this.x=t.x??0,this.y=t.y??0,this.width=t.width??0,this.height=t.height??0,this.words=t.words||[],t.text&&!t.words&&(this.words=t.text.split(" ").filter(t=>t.trim().length>0).map(t=>new F({string:t})))}text(){return this.wordStrings().join(" ")}wordStrings(){return this.words.map(t=>t.string)}},C=class t{results;stash;constructor(){if(this.constructor===t)throw new TypeError("Can not construct abstract class.");this.results=[],this.stash=[]}consumeAll(t){t.forEach(t=>this.consume(t))}consume(t){this.shouldStash(t)?(this.matchesStash(t)||this.flushStash(),this.pushOnStash(t)):(this.stash.length>0&&this.flushStash(),this.results.push(t))}pushOnStash(t){this.onPushOnStash(t),this.stash.push(t)}complete(){return this.stash.length>0&&this.flushStash(),this.results}matchesStash(t){if(0===this.stash.length)return!0;const e=this.stash[this.stash.length-1];return this.doMatchesStash(e,t)}flushStash(){this.stash.length>0&&(this.doFlushStash(this.stash,this.results),this.stash=[])}onPushOnStash(t){}shouldStash(t){throw new TypeError(" Do not call abstract method foo from child."+t)}doMatchesStash(t,e){throw new TypeError(" Do not call abstract method foo from child."+t+e)}doFlushStash(t,e){throw new TypeError(" Do not call abstract method foo from child."+t+e)}},N=class{footnoteLinks;footnotes;containLinks;formattedWords;constructor(t){this.footnoteLinks=t.footnoteLinks||[],this.footnotes=t.footnotes||[],this.containLinks=t.containLinks??!1,this.formattedWords=t.formattedWords??0}add(t){this.footnoteLinks=this.footnoteLinks.concat(t.footnoteLinks),this.footnotes=this.footnotes.concat(t.footnotes),this.containLinks=this.containLinks||t.containLinks,this.formattedWords+=t.formattedWords}};function M(t){t.sort((t,e)=>t.x-e.x)}var D={BOLD:{name:"BOLD",startSymbol:"<strong>",endSymbol:"</strong>"},OBLIQUE:{name:"OBLIQUE",startSymbol:"<em>",endSymbol:"</em>"},BOLD_OBLIQUE:{name:"BOLD_OBLIQUE",startSymbol:"<strong><em>",endSymbol:"</em></strong>"}},H={LINK:{name:"LINK",toText:t=>`<a href="${t}">${t}</a>`},FOOTNOTE_LINK:{name:"FOOTNOTE_LINK",attachWithoutWhitespace:!0,plainTextFormat:!0,toText:t=>`<sup><a href="#${t}">${t}</a></sup>`},FOOTNOTE:{name:"FOOTNOTE",toText:t=>`<p id="${t}">^${t}</p>`}},U=class{fontToFormats;constructor(t){this.fontToFormats=t}compact(t){M(t);const e=new B(this.fontToFormats);e.consumeAll(t.map(t=>new g({...t})));const s=e.complete();var n=0,o=0;return t.forEach(t=>{n=Math.max(n,t.height),o+=t.width}),new k({x:t[0].x,y:t[0].y,height:n,width:o,words:s,parsedElements:new N({footnoteLinks:e.footnoteLinks,footnotes:e.footnotes,containLinks:e.containLinks,formattedWords:e.formattedWords})})}},B=class extends C{fontToFormats;footnoteLinks;footnotes;formattedWords;containLinks;stashedNumber;firstY;currentItem;constructor(t){super(),this.fontToFormats=t,this.footnoteLinks=[],this.footnotes=[],this.formattedWords=0,this.containLinks=!1,this.stashedNumber=!1,this.currentItem=null}shouldStash(t){return this.firstY||(this.firstY=t.y),this.currentItem=t,!0}onPushOnStash(t){this.stashedNumber=n(t.text.trim())}doMatchesStash(t,e){if(this.fontToFormats.get(t.font)!==this.fontToFormats.get(e.font))return!1;const s=n(e.text.trim());return this.stashedNumber===s}doFlushStash(t,e){if(this.stashedNumber){const s=t.map(t=>t.text).join("").trim();t[0].y>this.firstY?(e.push(new F({string:`${s}`,type:H.FOOTNOTE_LINK})),this.footnoteLinks.push(parseInt(s))):this.currentItem&&this.currentItem.y<t[0].y?(e.push(new F({string:`${s}`,type:H.FOOTNOTE})),this.footnotes.push(s)):this.copyStashItemsAsText(t,e)}else this.copyStashItemsAsText(t,e)}copyStashItemsAsText(t,e){const s=this.fontToFormats.get(t[0].font);e.push(...this.itemsToWords(t,s))}itemsToWords(t,e){const s=(n=t,o="",r=null,n.forEach(t=>{var e=t.text;o.endsWith(" ")||e.startsWith(" ")||(r?t.x-r.x-r.width>5&&(o+=" "):a(t.text)&&(e+=" ")),o+=e,r=t}),o).split(" ");var n,o,r;const i=e?D[e]:null;return s.filter(t=>t.trim().length>0).map(t=>{var e=null;return t.startsWith("http:")?(this.containLinks=!0,e=H.LINK):t.startsWith("www.")&&(this.containLinks=!0,t=`http://${t}`,e=H.LINK),i&&this.formattedWords++,new F({string:t,type:e,format:i})})}};var P=class extends I{fontMap;constructor(t){super("Calculate Global Stats"),this.fontMap=t}transform(t){const e={},s={};var n,o=0;t.pages.forEach(t=>{t.items.forEach(t=>{t.height&&(e[t.height]=e[t.height]?e[t.height]+1:1,s[t.font]=s[t.font]?s[t.font]+1:1,t.height>o&&(o=t.height,n=t.font))})});const r=parseInt(A(e)),a=A(s),i={};t.pages.forEach(t=>{var e;t.items.forEach(t=>{if(t.height===r&&t.text.trim().length>0){if(e&&t.y!==e.y){const s=e.y-t.y;s>0&&(i[s]=i[s]?i[s]+1:1)}e=t}else e=null})});const h=parseInt(A(i)),l=[],c=new Map;this.fontMap?.forEach(function(t,e){l.push(e+" = "+t.name);const s=t.name.toLowerCase();var o=null;e===a?o=null:s.includes("bold")&&(s.includes("oblique")||s.includes("italic"))?o=D.BOLD_OBLIQUE:s.includes("bold")?o=D.BOLD:s.includes("oblique")||s.includes("italic")?o=D.OBLIQUE:s===n&&(o=D.BOLD),o&&c.set(e,o.name)}),l.sort();const m=t.pages.map(t=>({...t,items:t.items.map(t=>({...t}))}));return new S({...t,pages:m,globals:{mostUsedHeight:r,mostUsedFont:a,mostUsedDistance:h,maxHeight:o,maxHeightFont:n,fontToFormats:c},messages:["Items per height: "+JSON.stringify(e),"Items per font: "+JSON.stringify(s),"Items per distance: "+JSON.stringify(i),"Fonts:"+JSON.stringify(l)]})}};function A(t){var e=0,s="";return Object.keys(t).map(n=>{(!s||t[n]>e)&&(e=t[n],s=n)}),s}var $=class t extends x{constructor(e){if(super(e,k.name),this.constructor===t)throw new TypeError("Can not construct abstract class.")}completeTransform(t){return t.messages=[],t.pages.forEach(t=>{t.items=t.items.filter(t=>!t.annotation||t.annotation!==v),t.items.forEach(t=>t.annotation=null)}),t}},W=class{mostUsedDistance;constructor(t){this.mostUsedDistance=t.mostUsedDistance||12}group(t){const e=[];var s=[];return t.forEach(t=>{s.length>0&&Math.abs(s[0].y-t.y)>=this.mostUsedDistance/2&&(e.push(s),s=[]),s.push(t)}),e.push(s),e.forEach(t=>{M(t)}),e}},j={H1:{name:"H1",headline:!0,headlineLevel:1,toText:t=>"<h1>"+q(t.items,!0)+"</h1>"},H2:{name:"H2",headline:!0,headlineLevel:2,toText:t=>"<h2>"+q(t.items,!0)+"</h2>"},H3:{name:"H3",headline:!0,headlineLevel:3,toText:t=>"<h3>"+q(t.items,!0)+"</h3>"},H4:{name:"H4",headline:!0,headlineLevel:4,toText:t=>"<h4>"+q(t.items,!0)+"</h4>"},H5:{name:"H5",headline:!0,headlineLevel:5,toText:t=>"<h5>"+q(t.items,!0)+"</h5>"},H6:{name:"H6",headline:!0,headlineLevel:6,toText:t=>"<h6>"+q(t.items,!0)+"</h6>"},TOC:{name:"TOC",mergeToBlock:!0,toText:t=>q(t.items,!0)},FOOTNOTES:{name:"FOOTNOTES",mergeToBlock:!0,mergeFollowingNonTypedItems:!0,toText:t=>"<p>"+q(t.items,!1)+"</p>"},CODE:{name:"CODE",mergeToBlock:!0,toText:t=>"<code>"+q(t.items,!0)+"</code>"},LIST:{name:"LIST",mergeToBlock:!1,mergeFollowingNonTypedItemsWithSmallDistance:!0,toText:t=>"<ul>\n"+q(t.items,!1)+"</ul>"},PARAGRAPH:{name:"PARAGRAPH",toText:t=>"<p>"+q(t.items,!1)+"</p>"}};function q(t,e){var s,n="";const o=()=>{n+=s.endSymbol,s=null};return t.forEach((r,a)=>{var i;r&&(r.words.forEach((t,r)=>{const a=t.type,i=t.format;var h;!s||i&&i===s||o(),r>0&&(!a||!a.attachWithoutWhitespace)&&(1!==(h=t.string).length||"."!==h[0]&&"!"!==h[0]&&"?"!==h[0])&&(n+=" "),!i||s||e||(n+=(s=i).startSymbol),!a||e&&!a.plainTextFormat?n+=t.string:n+=a.toText(t.string)}),!s||a!==t.length-1&&(0===(i=t[a+1]).words.length?null:i.words[0].format)===s||o(),n+="\n")}),n}j.enumValueOf=function(t){return j[t]},j.isHeadline=function(t){return t&&2===t.name.length&&"H"===t.name[0]},j.blockToText=function(t){return t.type?t.type.toText(t):q(t.items,!1)},j.headlineByLevel=function(t){return 1===t?j.H1:2===t?j.H2:3===t?j.H3:4===t?j.H4:5===t?j.H5:(t>6&&console.warn("Unsupported headline level: "+t+" (supported are 1-6), defaulting to level 6"),j.H6)};var Y=class extends ${constructor(){super("Compact To Lines")}transform(t){const{mostUsedDistance:e,fontToFormats:s}=t.globals,n=[],o=[];var r=0,a=0;const i=new W({mostUsedDistance:e}),h=new U(s);return t.pages.forEach(t=>{if(t.items.length>0){const e=[];i.group(t.items).forEach(s=>{const i=h.compact(s);if(s.length>1&&(i.annotation=T,s.forEach(t=>{t.annotation=v,e.push(new k({...t}))})),0===i.words.length&&(i.annotation=v),e.push(i),i.parsedElements.formattedWords&&(a+=i.parsedElements.formattedWords),i.parsedElements.containLinks&&r++,i.parsedElements.footnoteLinks.length>0){const e=i.parsedElements.footnoteLinks.map(e=>({footnoteLink:e,page:t.index+1}));o.push.apply(o,e)}if(i.parsedElements.footnotes.length>0){i.type=j.FOOTNOTES;const e=i.parsedElements.footnotes.map(e=>({footnote:e,page:t.index+1}));n.push.apply(n,e)}}),t.items=e}}),new S({...t,messages:["Detected "+a+" formatted words","Found "+r+" links","Detected "+o.length+" footnotes links","Detected "+n.length+" footnotes"]})}};function R(t){var e=0;if(0===t.trim().length)return e;for(var n=0;n<t.length;n++){const o=t.charCodeAt(n);s(o)||32===o||160===o||(e=(e<<5)-e+o,e|=0)}return e}var V=class extends ${constructor(){super("Remove Repetitive Elements")}transform(t){const e=[],s={},n={};t.pages.forEach(t=>{const o=t.items.reduce((t,e)=>(e.y<t.minY?(t.minElements=[e],t.minY=e.y):e.y===t.minY&&t.minElements.push(e),e.y>t.maxY?(t.maxElements=[e],t.maxY=e.y):e.y===t.maxY&&t.maxElements.push(e),t),{minY:999,maxY:0,minElements:[],maxElements:[]}),r=R(o.minElements.reduce((t,e)=>t+e.text().toUpperCase(),"")),a=R(o.maxElements.reduce((t,e)=>t+e.text().toUpperCase(),""));e.push({minElements:o.minElements,maxElements:o.maxElements,minLineHash:r,maxLineHash:a}),s[r]=s[r]?s[r]+1:1,n[a]=n[a]?n[a]+1:1});var o=0,r=0;return t.pages.forEach((a,i)=>{s[e[i].minLineHash]>=Math.max(3,2*t.pages.length/3)&&(e[i].minElements.forEach(t=>{t.annotation=v}),r++),n[e[i].maxLineHash]>=Math.max(3,2*t.pages.length/3)&&(e[i].maxElements.forEach(t=>{t.annotation=v}),o++)}),new S({...t,messages:["Removed Header: "+o,"Removed Footers: "+r]})}},K=class extends ${constructor(){super("Vertical to Horizontal Text")}transform(t){var e=0;return t.pages.forEach(t=>{const s=new J;s.consumeAll(t.items),t.items=s.complete(),e+=s.foundVerticals}),new S({...t,messages:["Converted "+e+" verticals"]})}},J=class extends C{foundVerticals;constructor(){super(),this.foundVerticals=0}shouldStash(t){return 1===t.words.length&&1===t.words[0].string.length}doMatchesStash(t,e){return t.y-e.y>5&&t.words[0].type===e.words[0].type}doFlushStash(t,e){if(t.length>5){var s=[],n=999,o=0,r=0,a=0;t.forEach(t=>{t.annotation=v,e.push(t),s.push(t.words[0]),n=Math.min(n,t.x),o=Math.max(o,t.y),r+=t.width,a=Math.max(a,t.height)}),e.push(new k({...t[0],x:n,y:o,width:r,height:a,words:s,annotation:T})),this.foundVerticals++}else e.push(...t)}},Q=class{headlineCharCodes;stackedLineItems;stackedChars;constructor(t){this.headlineCharCodes=r(t.headline),this.stackedLineItems=[],this.stackedChars=0}consume(t){const e=r(t.text());if(this.matchAll(e)){if(this.stackedLineItems.push(t),this.stackedChars+=e.length,this.stackedChars===this.headlineCharCodes.length)return this.stackedLineItems}else this.stackedChars>0&&(this.stackedChars=0,this.stackedLineItems=[],this.consume(t));return null}matchAll(t){for(var e=0;e<t.length;e++){const s=this.headlineCharCodes[this.stackedChars+e];if(t[e]!==s)return!1}return!0}},_=class extends ${constructor(){super("Detect TOC")}transform(t){const e=[],r=Math.min(20,t.pages.length),a=new X;var i,h,c=[];t.pages.slice(0,r).forEach(t=>{var r=0;const l=new Set,m=[];var u,p;if(t.items.filter(t=>t.words.includes(t=>o(t.string,"."))).forEach(t=>{var e=t.words.filter(t=>!o(t.string,"."));const a=[];for(;e.length>0&&n(e[e.length-1].string);){const t=e.pop();a.unshift(t.string)}if(0===a.length&&e.length>0){const t=e[e.length-1];for(;s(t.string.charCodeAt(t.string.length-1));)a.unshift(t.string.charAt(t.string.length-1)),t.string=t.string.substring(0,t.string.length-1)}var i=a.length>0;i?(i=!0,u&&(e.push(...u),u=null),m.push(new Z({pageNumber:parseInt(a.join("")),lineItem:new k({...t,words:e})})),r++):h?(u&&l.add(p),u=e,p=t):h=t}),100*r/t.items.length>75){e.push(t.index+1),i=t,a.levelPageItems(m),c.push(...m);const s=[];t.items.forEach(t=>{l.has(t)||(t.annotation=v),s.push(t),t===h&&s.push(new k({...t,type:j.H2,annotation:T}))}),t.items=s}else h=null});var m=c.length;const u=[],p=[],d={};if(e.length>0){c.forEach(t=>{i.items.push(new k({words:[new F({string:" ".repeat(3*t.level)+"-"})].concat(t.lineItem.words),type:j.TOC,annotation:T}))});const e=function(t,e){for(var s of e){const e=z(t,s.lineItem.text());if(e)return e.index-s.pageNumber}return null}(t.pages.filter(t=>t.index>i.index),c);c.forEach(s=>{var n,o=t.pages[s.pageNumber+e];o&&((n=G(o,s.lineItem.text()))||(o=t.pages[s.pageNumber+e+1])&&(n=G(o,s.lineItem.text()))),n?function(t,e,s,n){s.headlineItems.forEach(t=>t.annotation=v);const o=j.headlineByLevel(e.level+2),r=s.headlineItems.reduce((t,e)=>Math.max(t,e.height),0);t.items.splice(s.lineIndex+1,0,new k({...s.headlineItems[0],words:e.lineItem.words,height:r,type:o,annotation:T}));var a=n[o.name];a?(a.min=Math.min(a.min,r),a.max=Math.max(a.max,r)):(a={min:r,max:r},n[o.name]=a)}(o,s,n,d):u.push(s)});var f=i.index+2,g=[];const s=e=>{g.length>0&&(g.forEach(s=>{const n=j.headlineByLevel(s.level+2),o=d[n.name];if(o){const[r,a]=function(t,e,s,n,o){const r=e.lineItem.text().toUpperCase();for(var a=n;a<=o;a++){const e=t[a-1];if(e){const t=e.items.findIndex(t=>!t.type&&!t.annotation&&t.height>=s.min&&t.height<=s.max&&l(r,t.text())>=.5);if(t>-1)return[a-1,t]}}return[-1,-1]}(t.pages,s,o,f,e);if(a>-1){const e=t.pages[r];e.items[a].annotation=v,e.items.splice(a+1,0,new k({...s.lineItem,type:n,annotation:T})),p.push(s)}}}),g=[])};u.length>0&&(c.forEach(t=>{u.includes(t)?g.push(t):(s(t.pageNumber),f=t.pageNumber)}),g.length>0&&s(t.pages.length))}const y=[];return y.push("Detected "+e.length+" table of content pages"),e.length>0&&(y.push("TOC headline heights: "+JSON.stringify(d)),y.push("Found TOC headlines: "+(m-u.length+p.length)+"/"+m)),u.length>0&&(y.push("Found TOC headlines (by size): "+p.map(t=>t.lineItem.text())),y.push("Missing TOC headlines: "+u.filter(t=>!p.includes(t)).map(t=>t.lineItem.text()+"=>"+t.pageNumber))),new S({...t,globals:{...t.globals,tocPages:e,headlineTypeToHeightRange:d},messages:y})}};function z(t,e){for(var s of t)if(G(s,e))return s;return null}function G(t,e){const s=new Q({headline:e});var n=0;for(var o of t.items){const t=s.consume(o);if(t)return{lineIndex:n,headlineItems:t};n++}return null}var X=class{levelByMethod;uniqueFonts;constructor(){this.levelByMethod=null,this.uniqueFonts=[]}levelPageItems(t){if(!this.levelByMethod)if(this.calculateUniqueX(t).length>1)this.levelByMethod=this.levelByXDiff;else{const e=this.calculateUniqueFonts(t);e.length>1?(this.uniqueFonts=e,this.levelByMethod=this.levelByFont):this.levelByMethod=this.levelToZero}this.levelByMethod(t)}levelByXDiff(t){const e=this.calculateUniqueX(t);t.forEach(t=>{t.level=e.indexOf(t.lineItem.x)})}levelByFont(t){t.forEach(t=>{t.level=this.uniqueFonts.indexOf(t.lineItem.font)})}levelToZero(t){t.forEach(t=>{t.level=0})}calculateUniqueX(t){var e=t.reduce(function(t,e){return t.indexOf(e.lineItem.x)<0&&t.push(e.lineItem.x),t},[]);return e.sort((t,e)=>t-e),e}calculateUniqueFonts(t){return t.reduce(function(t,e){return t.indexOf(e.lineItem.font)<0&&t.push(e.lineItem.font),t},[])}},Z=class{lineItem;pageNumber;level;constructor(t){this.lineItem=t.lineItem,this.pageNumber=t.pageNumber,this.level=0}},tt=class extends ${constructor(){super("Detect List Items")}transform(t){var e=0,s=0;return t.pages.forEach(t=>{const n=[];t.items.forEach(t=>{if(n.push(t),!t.type){var o=t.text();if(a(t.words[0].string))if(e++,"-"===t.words[0].string)t.annotation=L,t.type=j.LIST;else{t.annotation=v;const e=t.words.map(t=>new F({...t}));e[0].string="-",n.push(new k({...t,words:e,annotation:T,type:j.LIST}))}else/^[\s]*[\d]*[.][\s].*$/g.test(o)&&(s++,t.annotation=L,t.type=j.LIST)}}),t.items=n}),new S({...t,messages:["Detected "+e+" plain list items.","Detected "+s+" numbered list items."]})}},et=class extends ${constructor(){super("Detect Headers")}transform(t){const{tocPages:e,headlineTypeToHeightRange:s,mostUsedHeight:n,mostUsedDistance:o,mostUsedFont:r,maxHeight:a}=t.globals,h=e.length>0;var l=0;const c=function(t,e){const s=new Set;return t.forEach(t=>{t.items.forEach(n=>{n.type||n.height!==e||s.add(t)})}),s}(t.pages,a),m=n+(a-n)/4;if(c.forEach(t=>{t.items.forEach(t=>{const e=t.height;!t.type&&e>m&&(t.type=e===a?j.H1:j.H2,t.annotation=L,l++)})}),h)Object.keys(s).forEach(e=>{var o=s[e];o.max>n&&t.pages.forEach(t=>{t.items.forEach(t=>{t.type||t.height!==o.max||(t.annotation=L,t.type=j.enumValueOf(e),l++)})})});else{const e=[];t.pages.forEach(t=>{t.items.forEach(t=>{!t.type&&t.height>n&&!i(t.text())&&(e.includes(t.height)||e.push(t.height))})}),e.sort((t,e)=>e-t),e.forEach((e,s)=>{if(s+2<=6){const n=j.headlineByLevel(2+s);t.pages.forEach(t=>{t.items.forEach(t=>{t.type||t.height!==e||i(t.text())||(l++,t.annotation=L,t.type=n)})})}})}var u=1;if(t.pages.forEach(t=>{t.items.forEach(t=>{t.type&&t.type.headline&&(u=Math.max(u,t.type.headlineLevel))})}),u<6){const e=j.headlineByLevel(u+1);t.pages.forEach(t=>{var s;t.items.forEach(t=>{!t.type&&t.height===n&&t.font!==r&&(!s||s.y<t.y||s.type&&s.type.headline||s.y-t.y>2*o)&&t.text()===t.text().toUpperCase()&&(l++,t.annotation=L,t.type=e),s=t})})}return new S({...t,messages:["Detected "+l+" headlines."]})}};var st=class extends f{items;constructor(t){super(t),this.items=[],t.items&&t.items.forEach(t=>this.addItem(t))}addItem(t){if(this.type&&t.type&&this.type!==t.type)throw new Error(`Adding item of type ${t.type.name} to block of type ${this.type.name}`);this.type||(this.type=t.type),t.parsedElements&&(this.parsedElements?this.parsedElements.add(t.parsedElements):this.parsedElements=t.parsedElements);const e=new k({...t});e.type=null,this.items.push(e)}},nt=class t extends x{constructor(e){if(super(e,st.name),this.constructor===t)throw new TypeError("Can not construct abstract class.")}completeTransform(t){return t.messages=[],t.pages.forEach(t=>{t.items=t.items.filter(t=>!t.annotation||t.annotation!==v),t.items.forEach(t=>t.annotation=null)}),t}},ot=class extends nt{constructor(){super("Gather Blocks")}transform(t){const{mostUsedDistance:e}=t.globals;var s=0,n=0;return t.pages.map(t=>{n+=t.items.length;const o=[];var r=new st({});const a=()=>{r.items.length>1&&(r.annotation=L),o.push(r),r=new st({}),s++};var i=function(t){var e=999;return t.forEach(t=>{e=Math.min(e,t.x)}),999===e?null:e}(t.items);t.items.forEach(t=>{r.items.length>0&&function(t,e,s,n){if(t.type&&t.type.mergeFollowingNonTypedItems&&!e.type)return!1;const o=t.items[t.items.length-1],r=function(t,e,s,n){const o=t.y-e.y;if(o<0-n/2)return!0;var r=n+1;t.x>s&&e.x>s&&(r=n+n/2);return o>r}(o,e,s,n);if(t.type&&t.type.mergeFollowingNonTypedItemsWithSmallDistance&&!e.type&&!r)return!1;if(e.type!==t.type)return!0;return e.type?!e.type.mergeToBlock:r}(r,t,i,e)&&a(),r.addItem(t)}),r.items.length>0&&a(),t.items=o}),new S({...t,messages:["Gathered "+s+" blocks out of "+n+" line items"]})}};var rt=class extends nt{constructor(){super("$1")}transform(t){const e=t.globals.mostUsedHeight??0;var s=0;return t.pages.forEach(t=>{var n=function(t){var e=999;return t.forEach(t=>{t.items.forEach(t=>{e=Math.min(e,t.x)})}),999===e?null:e}(t.items);t.items.forEach(t=>{!t.type&&function(t,e,s){if(0===e.length)return!1;if(1===e.length)return e[0].x>t&&e[0].height<=s+1;for(var n of e)if(n.x===t)return!1;return!0}(n,t.items,e)&&(t.annotation=L,t.type=j.CODE,s++)})}),new S({...t,messages:["Detected "+s+" code/quote items."]})}};var at,it=class extends nt{constructor(){super("Level Lists")}transform(t){var e=0,s=0;return t.pages.forEach(t=>{t.items.filter(t=>t.type===j.LIST).forEach(t=>{var n,o=0;const r={};var a=!1;t.items.forEach(t=>{n?t.x>n?(o++,r[t.x]=o):t.x<n&&(o=r[t.x]):r[t.x]=0,o>0&&(t.words=[new F({string:" ".repeat(3*o)})].concat(t.words),a=!0),n=t.x}),e++,a?(s++,t.annotation=O):t.annotation=b})}),new S({...t,messages:["Modified "+s+" / "+e+" list blocks."]})}},ht=class extends x{constructor(){super("To Text Blocks","TextBlock")}transform(t){return t.pages.forEach(t=>{const e=[];t.items.forEach(t=>{const s=t.type?t.type.name:"Unknown";e.push({category:s,text:j.blockToText(t)})}),t.items=e}),new S({...t})}},lt=class extends x{constructor(){super("To HTML","String")}transform(t){return t.pages.forEach(t=>{var e="";t.items.forEach(t=>{let s;s="TOC"===t.category?t.text:t.text.replace(/(\r\n|\n|\r)/gm,"\n"),"LIST"!==t.category&&(s=s.split("- ").join("")),"CODE"===t.category&&(s=s.split("<code>").join("").split("</code>").join("")),e+=`<p>${s}</p>\n\n`}),t.items=[e]}),new S({...t})}};async function ct(t,e={}){const{addPageNumbers:s=!1,addCitation:n=!0,liteParseOptions:o={}}=e,r="string"==typeof t?await w(t,{responseType:"arraybuffer",timeout:10}):t;let a;try{({LiteParse:a}=await import("@llamaindex/liteparse"))}catch(p){return{error:`method: 'liteparse' requires the optional @llamaindex/liteparse dependency (Node.js only): ${p.message}`}}const i=new a({quiet:!0,ocrEnabled:!1,ocrFailureFatal:!1,...o});let l;try{l=await i.parse(new Uint8Array(r))}catch(p){return{error:p.message}}const c=l.pages.reduce((t,e)=>{const n=e.text.split(/\n{2,}/).filter(t=>t.trim().length>0).map(t=>h(t).replace(/\n/g,"<br/>")).join("</p><p>");return t+`<p id="page-${e.pageNum}">${s?` [${e.pageNum}] `:""}${n}</p>`},"");let m,u;return n&&(u=l.creator||l.producer,m=l.pages[0]?.text.split("\n").find(t=>t.trim().length>0)),{author:u,title:m,html:c,format:"pdf"}}async function mt(t,e={}){const{addPageNumbers:s=!1,addCitation:n=!0,liteParseOptions:o={}}=e,r="string"==typeof t?await w(t,{responseType:"arraybuffer",timeout:10}):t;let a;try{a=await import("@llamaindex/liteparse-wasm"),await async function(t){at||(at=t.default()),await at}(a)}catch(p){return{error:`method: 'liteparse-wasm' requires the optional @llamaindex/liteparse-wasm dependency: ${p.message}`}}const i=new a.LiteParse({quiet:!0,ocrEnabled:!1,ocrFailureFatal:!1,...o});let l;try{l=await i.parse(new Uint8Array(r))}catch(p){return{error:p.message}}const c=l.pages.reduce((t,e)=>{const n=e.text.split(/\n{2,}/).filter(t=>t.trim().length>0).map(t=>h(t).replace(/\n/g,"<br/>")).join("</p><p>");return t+`<p id="page-${e.pageNum}">${s?` [${e.pageNum}] `:""}${n}</p>`},"");let m,u;return n&&(u=l.creator||l.producer,m=l.pages[0]?.text.split("\n").find(t=>t.trim().length>0)),{author:u,title:m,html:c,format:"pdf"}}exports.convertPDFToHTML=async function(t,e={}){if("liteparse"===e.method){const{method:s,...n}=e;return ct(t,n)}if("liteparse-wasm"===e.method){const{method:s,...n}=e;return mt(t,n)}var{addPageNumbers:s=!1,addCitation:n=!0}=e,o="string"==typeof t?await w(t,{responseType:"arraybuffer",timeout:10}):t;let r;try{let{resolvePDFJS:t}=await import("https://cdn.jsdelivr.net/npm/pdfjs-serverless@1.1.0/+esm");const{getDocument:e}=await t();r=await e({data:new Uint8Array(o),useSystemFonts:!0,verbosity:0}).promise}catch(T){return{error:T.message}}const a=[...Array(r.numPages).keys()].map(t=>new y({index:t}));let i,h={};for(let d=1;d<=r.numPages;d++){const t=await r.getPage(d),e=await t.getTextContent();if(!(Object.keys(h).length<10)){i=p(h);break}h=u(h,t.pageNumber-1,e.items)}let l=i?i.pageNum:0;for(let u=1;u<=r.numPages;u++){const t=await r.getPage(u);await t.getOperatorList();const e=t.getViewport({scale:1});let s=await t.getTextContent();i&&t.pageIndex>=i.pageIndex&&(s=d(s,l),l++);const n=s.items.map(t=>{const s=[1,0,0,1,0,0];for(let r=0;r<6;r++)s[r]+=t.transform[r]*e.transform[r%2?3:0],r%2&&(s[r+1]+=t.transform[r]*e.transform[1]);const n=Math.sqrt(s[2]*s[2]+s[3]*s[3]),o=t.height/n;return new g({x:Math.round(t.transform[4]),y:Math.round(t.transform[5]),width:Math.round(t.width),height:Math.round(o<=1?t.height:o),text:t.str,font:t.fontName})});a[t.pageNumber-1].items=n}var c=new S({pages:a});let m;[new P,new Y,new V,new K,new _,new et,new tt,new ot,new rt,new it,new ht,new lt].forEach(t=>{m&&(c=m.completeTransform(c)),c=t.transform(c),m=t});var f=c.pages.reduce((t,e,n)=>t+`<p id="page-${n+1}">${s?` [${n+1}] `:""}${e.items.join('</p><p id="page-'+n+'">')}</p>`,"");if(n){var{Author:x,Title:E}=(await r.getMetadata()).info;E=f.slice(0,400).match(/<h[0-9]>(.*?)<\/h[0-9]>/)?.[1]||E}return{author:x,title:E,html:f,format:"pdf"}},exports.convertPDFToHTMLWithLiteParse=ct,exports.convertPDFToHTMLWithLiteParseWasm=mt,exports.detectPdfNeedsOcr=async function(t,e={}){const s="string"==typeof t?await w(t,{responseType:"arraybuffer",timeout:10}):t,{LiteParse:n}=await import("@llamaindex/liteparse"),o=await new n({quiet:!0,...e.liteParseOptions}).isComplex(new Uint8Array(s));return{needsOcr:o.some(t=>t.needsOcr),pages:o,reasons:[...new Set(o.flatMap(t=>t.reasons))]}};
|
package/dist/pdf-to-html.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { convertPDFToHTMLWithLiteParse, LiteParseHTMLOptions } from './liteparse-to-html';
|
|
2
|
+
import { convertPDFToHTMLWithLiteParseWasm } from './liteparse-wasm-to-html';
|
|
2
3
|
/**
|
|
3
4
|
* Which parsing engine {@link convertPDFToHTML} runs.
|
|
4
5
|
* - `"ts-block-algorithm"` (default) — the pure-TS pipeline in this file: groups
|
|
@@ -7,8 +8,12 @@ import { convertPDFToHTMLWithLiteParse, LiteParseHTMLOptions } from './liteparse
|
|
|
7
8
|
* - `"liteparse"` — delegates to [LiteParse](https://github.com/run-llama/liteparse),
|
|
8
9
|
* a native/OCR-capable parser. Node.js only (ships a napi addon), and requires
|
|
9
10
|
* the optional `@llamaindex/liteparse` dependency to be installed.
|
|
11
|
+
* - `"liteparse-wasm"` — delegates to LiteParse's WebAssembly build. Runs
|
|
12
|
+
* anywhere WASM does — browsers, Cloudflare Workers, and Node.js — and
|
|
13
|
+
* requires the optional `@llamaindex/liteparse-wasm` dependency to be
|
|
14
|
+
* installed. OCR requires passing an `ocrEngine` callback (e.g. tesseract-js).
|
|
10
15
|
*/
|
|
11
|
-
export type ParseMethod = "ts-block-algorithm" | "liteparse";
|
|
16
|
+
export type ParseMethod = "ts-block-algorithm" | "liteparse" | "liteparse-wasm";
|
|
12
17
|
/**
|
|
13
18
|
* Extracts formatted text from PDF with parsing of linebreaks ,
|
|
14
19
|
* page headers, footnotes, and section headings. Supports fonts, links, bold,
|
|
@@ -55,5 +60,7 @@ export declare function convertPDFToHTML(pdfURLOrBuffer: any, options?: {
|
|
|
55
60
|
}>;
|
|
56
61
|
export { convertPDFToHTMLWithLiteParse };
|
|
57
62
|
export type { LiteParseHTMLOptions } from './liteparse-to-html';
|
|
63
|
+
export { convertPDFToHTMLWithLiteParseWasm };
|
|
64
|
+
export type { LiteParseWasmHTMLOptions } from './liteparse-wasm-to-html';
|
|
58
65
|
export { detectPdfNeedsOcr } from './detect-needs-ocr';
|
|
59
66
|
export type { DetectPdfNeedsOcrOptions, PdfOcrAssessment, } from './detect-needs-ocr';
|
package/dist/pdf-to-html.es.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
function t(t){for(;32===t.charCodeAt(0);)t=t.substring(1,t.length);return t}function e(t){for(;32===t.charCodeAt(t.length-1);)t=t.substring(0,t.length-1);return t}function s(t){return t>=48&&t<=57}function n(t){for(var e=0;e<t.length;e++)if(!s(t.charCodeAt(e)))return!1;return!0}function o(t,e){const s=e.charCodeAt(0);for(var n=0;n<t.length;n++)if(t.charCodeAt(n)!==s)return!1;return!0}function r(t){return function(t){const e=[];for(var s=0;s<t.length;s++)e.push(t.charCodeAt(s));return e}(t=t.toUpperCase()).filter(t=>32!==t&&9!==t&&46!==t)}function a(t){if(t.length>1)return!1;const e=t.charAt(0);return"-"===e||"•"===e||"–"===e}function i(t){return/^[\s]*[-•–][\s].*$/g.test(t)}function h(t,e){const s=new Set(t.toUpperCase().split(" ")),n=new Set(e.toUpperCase().split(" "));return new Set([...s].filter(t=>n.has(t))).size/Math.max(s.size,n.size)}var l=(t,e,s)=>Math.floor(t/e*s),c=(s,o,r)=>{for(const{str:a}of s){const s=e(t(a));n(s)&&(o[r]||(o[r]=[]),o[r].push(Number(s)))}return o},m=(t,e,s)=>{const n=l(1,6,s.length),o=l(5,6,s.length),r=c(s.slice(0,n),t,e);return c(s.slice(o),r,e)},u=t=>{let e=0;const s=Object.keys(t);if(0!==s.length&&1!==s.length)for(let n=0;n<s.length-1;n++){const o=t[s[n]],r=t[s[n+1]],a=e;for(let t=0;t<o.length&&e<2;t++)for(let a=0;a<r.length&&e<2;a++){const i=Number(s[n+1])-Number(s[n]);(o[t]+1===r[a]||i>1&&o[t]+i===r[a])&&e++}let i=n>0?Object.entries(t)[n-1]:Object.entries(t)[n];if(a===e)e=0,i=Object.entries(t)[n];else if(e>=2)return{pageIndex:Number(i[0]),pageNum:i[1][0]}}},p=(t,e)=>{const s={items:[...t.items]},n=l(1,6,s.items.length),o=l(5,6,s.items.length);return s.items=s.items.filter((t,r)=>{const a=r>0&&r<n,i=r>o&&r<s.items.length;return a||i?Number(t.str)!==Number(e):t}),s},f=class t{type;annotation;parsedElements;constructor(e){if(this.constructor===t)throw new TypeError("Can not construct abstract class.");this.type=e.type??null,this.annotation=e.annotation??null,this.parsedElements=e.parsedElements??null}},d=class extends f{x;y;width;height;text;font;lineFormat;unopenedFormat;unclosedFormat;constructor(t){super(t),this.x=t.x,this.y=t.y,this.width=t.width,this.height=t.height,this.text=t.text,this.font=t.font,this.lineFormat=t.lineFormat??null,this.unopenedFormat=t.unopenedFormat??null,this.unclosedFormat=t.unclosedFormat??null}},g=class{index;items;constructor(t){this.index=t.index,this.items=t.items||[]}};async function y(t,e={}){const s=e.timeout?1e3*e.timeout:1e4,n=new AbortController,o=setTimeout(()=>n.abort(),s);try{const s=await fetch(t,{signal:n.signal});if(clearTimeout(o),!s.ok)throw new Error(`HTTP ${s.status}`);return"arraybuffer"===e.responseType?await s.arrayBuffer():await s.text()}catch(r){throw clearTimeout(o),r}}var w=class t{name;itemType;constructor(e,s){if(this.constructor===t)throw new TypeError("Can not construct abstract class.");if(this.transform===t.prototype.transform)throw new TypeError("Please implement abstract method 'transform()'.");this.name=e,this.itemType=s}transform(t){throw new TypeError("Do not call abstract method foo from child.")}completeTransform(t){return t.messages=[],t}},x=class{category;color;constructor(t){this.category=t.category,this.color=t.color}},E=new x({category:"Added",color:"green"}),T=new x({category:"Removed",color:"red"}),v=new x({category:"Unchanged",color:"brown"}),b=new x({category:"Detected",color:"green"}),L=new x({category:"Modified",color:"green"}),O=class t extends w{constructor(e){if(super(e,d.name),this.constructor===t)throw new TypeError("Can not construct abstract class.")}completeTransform(t){return t.messages=[],t.pages.forEach(t=>{t.items=t.items.filter(t=>!t.annotation||t.annotation!==T),t.items.forEach(t=>t.annotation=null)}),t}},I=class{pages;globals;messages;constructor(t){this.pages=t.pages||[],this.globals=t.globals||{},this.messages=t.messages||[]}},S=class{string;type;format;constructor(t){this.string=t.string,this.type=t.type??null,this.format=t.format??null}},k=class extends f{x;y;width;height;words;constructor(t){super(t),this.x=t.x??0,this.y=t.y??0,this.width=t.width??0,this.height=t.height??0,this.words=t.words||[],t.text&&!t.words&&(this.words=t.text.split(" ").filter(t=>t.trim().length>0).map(t=>new S({string:t})))}text(){return this.wordStrings().join(" ")}wordStrings(){return this.words.map(t=>t.string)}},C=class t{results;stash;constructor(){if(this.constructor===t)throw new TypeError("Can not construct abstract class.");this.results=[],this.stash=[]}consumeAll(t){t.forEach(t=>this.consume(t))}consume(t){this.shouldStash(t)?(this.matchesStash(t)||this.flushStash(),this.pushOnStash(t)):(this.stash.length>0&&this.flushStash(),this.results.push(t))}pushOnStash(t){this.onPushOnStash(t),this.stash.push(t)}complete(){return this.stash.length>0&&this.flushStash(),this.results}matchesStash(t){if(0===this.stash.length)return!0;const e=this.stash[this.stash.length-1];return this.doMatchesStash(e,t)}flushStash(){this.stash.length>0&&(this.doFlushStash(this.stash,this.results),this.stash=[])}onPushOnStash(t){}shouldStash(t){throw new TypeError(" Do not call abstract method foo from child."+t)}doMatchesStash(t,e){throw new TypeError(" Do not call abstract method foo from child."+t+e)}doFlushStash(t,e){throw new TypeError(" Do not call abstract method foo from child."+t+e)}},F=class{footnoteLinks;footnotes;containLinks;formattedWords;constructor(t){this.footnoteLinks=t.footnoteLinks||[],this.footnotes=t.footnotes||[],this.containLinks=t.containLinks??!1,this.formattedWords=t.formattedWords??0}add(t){this.footnoteLinks=this.footnoteLinks.concat(t.footnoteLinks),this.footnotes=this.footnotes.concat(t.footnotes),this.containLinks=this.containLinks||t.containLinks,this.formattedWords+=t.formattedWords}};function N(t){t.sort((t,e)=>t.x-e.x)}var D={BOLD:{name:"BOLD",startSymbol:"<strong>",endSymbol:"</strong>"},OBLIQUE:{name:"OBLIQUE",startSymbol:"<em>",endSymbol:"</em>"},BOLD_OBLIQUE:{name:"BOLD_OBLIQUE",startSymbol:"<strong><em>",endSymbol:"</em></strong>"}},H={LINK:{name:"LINK",toText:t=>`<a href="${t}">${t}</a>`},FOOTNOTE_LINK:{name:"FOOTNOTE_LINK",attachWithoutWhitespace:!0,plainTextFormat:!0,toText:t=>`<sup><a href="#${t}">${t}</a></sup>`},FOOTNOTE:{name:"FOOTNOTE",toText:t=>`<p id="${t}">^${t}</p>`}},M=class{fontToFormats;constructor(t){this.fontToFormats=t}compact(t){N(t);const e=new B(this.fontToFormats);e.consumeAll(t.map(t=>new d({...t})));const s=e.complete();var n=0,o=0;return t.forEach(t=>{n=Math.max(n,t.height),o+=t.width}),new k({x:t[0].x,y:t[0].y,height:n,width:o,words:s,parsedElements:new F({footnoteLinks:e.footnoteLinks,footnotes:e.footnotes,containLinks:e.containLinks,formattedWords:e.formattedWords})})}},B=class extends C{fontToFormats;footnoteLinks;footnotes;formattedWords;containLinks;stashedNumber;firstY;currentItem;constructor(t){super(),this.fontToFormats=t,this.footnoteLinks=[],this.footnotes=[],this.formattedWords=0,this.containLinks=!1,this.stashedNumber=!1,this.currentItem=null}shouldStash(t){return this.firstY||(this.firstY=t.y),this.currentItem=t,!0}onPushOnStash(t){this.stashedNumber=n(t.text.trim())}doMatchesStash(t,e){if(this.fontToFormats.get(t.font)!==this.fontToFormats.get(e.font))return!1;const s=n(e.text.trim());return this.stashedNumber===s}doFlushStash(t,e){if(this.stashedNumber){const s=t.map(t=>t.text).join("").trim();t[0].y>this.firstY?(e.push(new S({string:`${s}`,type:H.FOOTNOTE_LINK})),this.footnoteLinks.push(parseInt(s))):this.currentItem&&this.currentItem.y<t[0].y?(e.push(new S({string:`${s}`,type:H.FOOTNOTE})),this.footnotes.push(s)):this.copyStashItemsAsText(t,e)}else this.copyStashItemsAsText(t,e)}copyStashItemsAsText(t,e){const s=this.fontToFormats.get(t[0].font);e.push(...this.itemsToWords(t,s))}itemsToWords(t,e){const s=(n=t,o="",r=null,n.forEach(t=>{var e=t.text;o.endsWith(" ")||e.startsWith(" ")||(r?t.x-r.x-r.width>5&&(o+=" "):a(t.text)&&(e+=" ")),o+=e,r=t}),o).split(" ");var n,o,r;const i=e?D[e]:null;return s.filter(t=>t.trim().length>0).map(t=>{var e=null;return t.startsWith("http:")?(this.containLinks=!0,e=H.LINK):t.startsWith("www.")&&(this.containLinks=!0,t=`http://${t}`,e=H.LINK),i&&this.formattedWords++,new S({string:t,type:e,format:i})})}};var U=class extends O{fontMap;constructor(t){super("Calculate Global Stats"),this.fontMap=t}transform(t){const e={},s={};var n,o=0;t.pages.forEach(t=>{t.items.forEach(t=>{t.height&&(e[t.height]=e[t.height]?e[t.height]+1:1,s[t.font]=s[t.font]?s[t.font]+1:1,t.height>o&&(o=t.height,n=t.font))})});const r=parseInt(A(e)),a=A(s),i={};t.pages.forEach(t=>{var e;t.items.forEach(t=>{if(t.height===r&&t.text.trim().length>0){if(e&&t.y!==e.y){const s=e.y-t.y;s>0&&(i[s]=i[s]?i[s]+1:1)}e=t}else e=null})});const h=parseInt(A(i)),l=[],c=/* @__PURE__ */new Map;this.fontMap?.forEach(function(t,e){l.push(e+" = "+t.name);const s=t.name.toLowerCase();var o=null;e===a?o=null:s.includes("bold")&&(s.includes("oblique")||s.includes("italic"))?o=D.BOLD_OBLIQUE:s.includes("bold")?o=D.BOLD:s.includes("oblique")||s.includes("italic")?o=D.OBLIQUE:s===n&&(o=D.BOLD),o&&c.set(e,o.name)}),l.sort();const m=t.pages.map(t=>({...t,items:t.items.map(t=>({...t}))}));return new I({...t,pages:m,globals:{mostUsedHeight:r,mostUsedFont:a,mostUsedDistance:h,maxHeight:o,maxHeightFont:n,fontToFormats:c},messages:["Items per height: "+JSON.stringify(e),"Items per font: "+JSON.stringify(s),"Items per distance: "+JSON.stringify(i),"Fonts:"+JSON.stringify(l)]})}};function A(t){var e=0,s="";return Object.keys(t).map(n=>{(!s||t[n]>e)&&(e=t[n],s=n)}),s}var P=class t extends w{constructor(e){if(super(e,k.name),this.constructor===t)throw new TypeError("Can not construct abstract class.")}completeTransform(t){return t.messages=[],t.pages.forEach(t=>{t.items=t.items.filter(t=>!t.annotation||t.annotation!==T),t.items.forEach(t=>t.annotation=null)}),t}},$=class{mostUsedDistance;constructor(t){this.mostUsedDistance=t.mostUsedDistance||12}group(t){const e=[];var s=[];return t.forEach(t=>{s.length>0&&Math.abs(s[0].y-t.y)>=this.mostUsedDistance/2&&(e.push(s),s=[]),s.push(t)}),e.push(s),e.forEach(t=>{N(t)}),e}},W={H1:{name:"H1",headline:!0,headlineLevel:1,toText:t=>"<h1>"+j(t.items,!0)+"</h1>"},H2:{name:"H2",headline:!0,headlineLevel:2,toText:t=>"<h2>"+j(t.items,!0)+"</h2>"},H3:{name:"H3",headline:!0,headlineLevel:3,toText:t=>"<h3>"+j(t.items,!0)+"</h3>"},H4:{name:"H4",headline:!0,headlineLevel:4,toText:t=>"<h4>"+j(t.items,!0)+"</h4>"},H5:{name:"H5",headline:!0,headlineLevel:5,toText:t=>"<h5>"+j(t.items,!0)+"</h5>"},H6:{name:"H6",headline:!0,headlineLevel:6,toText:t=>"<h6>"+j(t.items,!0)+"</h6>"},TOC:{name:"TOC",mergeToBlock:!0,toText:t=>j(t.items,!0)},FOOTNOTES:{name:"FOOTNOTES",mergeToBlock:!0,mergeFollowingNonTypedItems:!0,toText:t=>"<p>"+j(t.items,!1)+"</p>"},CODE:{name:"CODE",mergeToBlock:!0,toText:t=>"<code>"+j(t.items,!0)+"</code>"},LIST:{name:"LIST",mergeToBlock:!1,mergeFollowingNonTypedItemsWithSmallDistance:!0,toText:t=>"<ul>\n"+j(t.items,!1)+"</ul>"},PARAGRAPH:{name:"PARAGRAPH",toText:t=>"<p>"+j(t.items,!1)+"</p>"}};function j(t,e){var s,n="";const o=()=>{n+=s.endSymbol,s=null};return t.forEach((r,a)=>{var i;r&&(r.words.forEach((t,r)=>{const a=t.type,i=t.format;var h;!s||i&&i===s||o(),r>0&&(!a||!a.attachWithoutWhitespace)&&(1!==(h=t.string).length||"."!==h[0]&&"!"!==h[0]&&"?"!==h[0])&&(n+=" "),!i||s||e||(n+=(s=i).startSymbol),!a||e&&!a.plainTextFormat?n+=t.string:n+=a.toText(t.string)}),!s||a!==t.length-1&&(0===(i=t[a+1]).words.length?null:i.words[0].format)===s||o(),n+="\n")}),n}W.enumValueOf=function(t){return W[t]},W.isHeadline=function(t){return t&&2===t.name.length&&"H"===t.name[0]},W.blockToText=function(t){return t.type?t.type.toText(t):j(t.items,!1)},W.headlineByLevel=function(t){return 1===t?W.H1:2===t?W.H2:3===t?W.H3:4===t?W.H4:5===t?W.H5:(t>6&&console.warn("Unsupported headline level: "+t+" (supported are 1-6), defaulting to level 6"),W.H6)};var q=class extends P{constructor(){super("Compact To Lines")}transform(t){const{mostUsedDistance:e,fontToFormats:s}=t.globals,n=[],o=[];var r=0,a=0;const i=new $({mostUsedDistance:e}),h=new M(s);return t.pages.forEach(t=>{if(t.items.length>0){const e=[];i.group(t.items).forEach(s=>{const i=h.compact(s);if(s.length>1&&(i.annotation=E,s.forEach(t=>{t.annotation=T,e.push(new k({...t}))})),0===i.words.length&&(i.annotation=T),e.push(i),i.parsedElements.formattedWords&&(a+=i.parsedElements.formattedWords),i.parsedElements.containLinks&&r++,i.parsedElements.footnoteLinks.length>0){const e=i.parsedElements.footnoteLinks.map(e=>({footnoteLink:e,page:t.index+1}));o.push.apply(o,e)}if(i.parsedElements.footnotes.length>0){i.type=W.FOOTNOTES;const e=i.parsedElements.footnotes.map(e=>({footnote:e,page:t.index+1}));n.push.apply(n,e)}}),t.items=e}}),new I({...t,messages:["Detected "+a+" formatted words","Found "+r+" links","Detected "+o.length+" footnotes links","Detected "+n.length+" footnotes"]})}};function Y(t){var e=0;if(0===t.trim().length)return e;for(var n=0;n<t.length;n++){const o=t.charCodeAt(n);s(o)||32===o||160===o||(e=(e<<5)-e+o,e|=0)}return e}var R=class extends P{constructor(){super("Remove Repetitive Elements")}transform(t){const e=[],s={},n={};t.pages.forEach(t=>{const o=t.items.reduce((t,e)=>(e.y<t.minY?(t.minElements=[e],t.minY=e.y):e.y===t.minY&&t.minElements.push(e),e.y>t.maxY?(t.maxElements=[e],t.maxY=e.y):e.y===t.maxY&&t.maxElements.push(e),t),{minY:999,maxY:0,minElements:[],maxElements:[]}),r=Y(o.minElements.reduce((t,e)=>t+e.text().toUpperCase(),"")),a=Y(o.maxElements.reduce((t,e)=>t+e.text().toUpperCase(),""));e.push({minElements:o.minElements,maxElements:o.maxElements,minLineHash:r,maxLineHash:a}),s[r]=s[r]?s[r]+1:1,n[a]=n[a]?n[a]+1:1});var o=0,r=0;return t.pages.forEach((a,i)=>{s[e[i].minLineHash]>=Math.max(3,2*t.pages.length/3)&&(e[i].minElements.forEach(t=>{t.annotation=T}),r++),n[e[i].maxLineHash]>=Math.max(3,2*t.pages.length/3)&&(e[i].maxElements.forEach(t=>{t.annotation=T}),o++)}),new I({...t,messages:["Removed Header: "+o,"Removed Footers: "+r]})}},V=class extends P{constructor(){super("Vertical to Horizontal Text")}transform(t){var e=0;return t.pages.forEach(t=>{const s=new K;s.consumeAll(t.items),t.items=s.complete(),e+=s.foundVerticals}),new I({...t,messages:["Converted "+e+" verticals"]})}},K=class extends C{foundVerticals;constructor(){super(),this.foundVerticals=0}shouldStash(t){return 1===t.words.length&&1===t.words[0].string.length}doMatchesStash(t,e){return t.y-e.y>5&&t.words[0].type===e.words[0].type}doFlushStash(t,e){if(t.length>5){var s=[],n=999,o=0,r=0,a=0;t.forEach(t=>{t.annotation=T,e.push(t),s.push(t.words[0]),n=Math.min(n,t.x),o=Math.max(o,t.y),r+=t.width,a=Math.max(a,t.height)}),e.push(new k({...t[0],x:n,y:o,width:r,height:a,words:s,annotation:E})),this.foundVerticals++}else e.push(...t)}},J=class{headlineCharCodes;stackedLineItems;stackedChars;constructor(t){this.headlineCharCodes=r(t.headline),this.stackedLineItems=[],this.stackedChars=0}consume(t){const e=r(t.text());if(this.matchAll(e)){if(this.stackedLineItems.push(t),this.stackedChars+=e.length,this.stackedChars===this.headlineCharCodes.length)return this.stackedLineItems}else this.stackedChars>0&&(this.stackedChars=0,this.stackedLineItems=[],this.consume(t));return null}matchAll(t){for(var e=0;e<t.length;e++){const s=this.headlineCharCodes[this.stackedChars+e];if(t[e]!==s)return!1}return!0}},Q=class extends P{constructor(){super("Detect TOC")}transform(t){const e=[],r=Math.min(20,t.pages.length),a=new G;var i,l,c=[];t.pages.slice(0,r).forEach(t=>{var r=0;const h=/* @__PURE__ */new Set,m=[];var u,p;if(t.items.filter(t=>t.words.includes(t=>o(t.string,"."))).forEach(t=>{var e=t.words.filter(t=>!o(t.string,"."));const a=[];for(;e.length>0&&n(e[e.length-1].string);){const t=e.pop();a.unshift(t.string)}if(0===a.length&&e.length>0){const t=e[e.length-1];for(;s(t.string.charCodeAt(t.string.length-1));)a.unshift(t.string.charAt(t.string.length-1)),t.string=t.string.substring(0,t.string.length-1)}var i=a.length>0;i?(i=!0,u&&(e.push(...u),u=null),m.push(new X({pageNumber:parseInt(a.join("")),lineItem:new k({...t,words:e})})),r++):l?(u&&h.add(p),u=e,p=t):l=t}),100*r/t.items.length>75){e.push(t.index+1),i=t,a.levelPageItems(m),c.push(...m);const s=[];t.items.forEach(t=>{h.has(t)||(t.annotation=T),s.push(t),t===l&&s.push(new k({...t,type:W.H2,annotation:E}))}),t.items=s}else l=null});var m=c.length;const u=[],p=[],f={};if(e.length>0){c.forEach(t=>{i.items.push(new k({words:[new S({string:" ".repeat(3*t.level)+"-"})].concat(t.lineItem.words),type:W.TOC,annotation:E}))});const e=function(t,e){for(var s of e){const e=_(t,s.lineItem.text());if(e)return e.index-s.pageNumber}return null}(t.pages.filter(t=>t.index>i.index),c);c.forEach(s=>{var n,o=t.pages[s.pageNumber+e];o&&((n=z(o,s.lineItem.text()))||(o=t.pages[s.pageNumber+e+1])&&(n=z(o,s.lineItem.text()))),n?function(t,e,s,n){s.headlineItems.forEach(t=>t.annotation=T);const o=W.headlineByLevel(e.level+2),r=s.headlineItems.reduce((t,e)=>Math.max(t,e.height),0);t.items.splice(s.lineIndex+1,0,new k({...s.headlineItems[0],words:e.lineItem.words,height:r,type:o,annotation:E}));var a=n[o.name];a?(a.min=Math.min(a.min,r),a.max=Math.max(a.max,r)):(a={min:r,max:r},n[o.name]=a)}(o,s,n,f):u.push(s)});var d=i.index+2,g=[];const s=e=>{g.length>0&&(g.forEach(s=>{const n=W.headlineByLevel(s.level+2),o=f[n.name];if(o){const[r,a]=function(t,e,s,n,o){const r=e.lineItem.text().toUpperCase();for(var a=n;a<=o;a++){const e=t[a-1];if(e){const t=e.items.findIndex(t=>!t.type&&!t.annotation&&t.height>=s.min&&t.height<=s.max&&h(r,t.text())>=.5);if(t>-1)return[a-1,t]}}return[-1,-1]}(t.pages,s,o,d,e);if(a>-1){const e=t.pages[r];e.items[a].annotation=T,e.items.splice(a+1,0,new k({...s.lineItem,type:n,annotation:E})),p.push(s)}}}),g=[])};u.length>0&&(c.forEach(t=>{u.includes(t)?g.push(t):(s(t.pageNumber),d=t.pageNumber)}),g.length>0&&s(t.pages.length))}const y=[];return y.push("Detected "+e.length+" table of content pages"),e.length>0&&(y.push("TOC headline heights: "+JSON.stringify(f)),y.push("Found TOC headlines: "+(m-u.length+p.length)+"/"+m)),u.length>0&&(y.push("Found TOC headlines (by size): "+p.map(t=>t.lineItem.text())),y.push("Missing TOC headlines: "+u.filter(t=>!p.includes(t)).map(t=>t.lineItem.text()+"=>"+t.pageNumber))),new I({...t,globals:{...t.globals,tocPages:e,headlineTypeToHeightRange:f},messages:y})}};function _(t,e){for(var s of t)if(z(s,e))return s;return null}function z(t,e){const s=new J({headline:e});var n=0;for(var o of t.items){const t=s.consume(o);if(t)return{lineIndex:n,headlineItems:t};n++}return null}var G=class{levelByMethod;uniqueFonts;constructor(){this.levelByMethod=null,this.uniqueFonts=[]}levelPageItems(t){if(!this.levelByMethod)if(this.calculateUniqueX(t).length>1)this.levelByMethod=this.levelByXDiff;else{const e=this.calculateUniqueFonts(t);e.length>1?(this.uniqueFonts=e,this.levelByMethod=this.levelByFont):this.levelByMethod=this.levelToZero}this.levelByMethod(t)}levelByXDiff(t){const e=this.calculateUniqueX(t);t.forEach(t=>{t.level=e.indexOf(t.lineItem.x)})}levelByFont(t){t.forEach(t=>{t.level=this.uniqueFonts.indexOf(t.lineItem.font)})}levelToZero(t){t.forEach(t=>{t.level=0})}calculateUniqueX(t){var e=t.reduce(function(t,e){return t.indexOf(e.lineItem.x)<0&&t.push(e.lineItem.x),t},[]);return e.sort((t,e)=>t-e),e}calculateUniqueFonts(t){return t.reduce(function(t,e){return t.indexOf(e.lineItem.font)<0&&t.push(e.lineItem.font),t},[])}},X=class{lineItem;pageNumber;level;constructor(t){this.lineItem=t.lineItem,this.pageNumber=t.pageNumber,this.level=0}},Z=class extends P{constructor(){super("Detect List Items")}transform(t){var e=0,s=0;return t.pages.forEach(t=>{const n=[];t.items.forEach(t=>{if(n.push(t),!t.type){var o=t.text();if(a(t.words[0].string))if(e++,"-"===t.words[0].string)t.annotation=b,t.type=W.LIST;else{t.annotation=T;const e=t.words.map(t=>new S({...t}));e[0].string="-",n.push(new k({...t,words:e,annotation:E,type:W.LIST}))}else/^[\s]*[\d]*[.][\s].*$/g.test(o)&&(s++,t.annotation=b,t.type=W.LIST)}}),t.items=n}),new I({...t,messages:["Detected "+e+" plain list items.","Detected "+s+" numbered list items."]})}},tt=class extends P{constructor(){super("Detect Headers")}transform(t){const{tocPages:e,headlineTypeToHeightRange:s,mostUsedHeight:n,mostUsedDistance:o,mostUsedFont:r,maxHeight:a}=t.globals,h=e.length>0;var l=0;const c=function(t,e){const s=/* @__PURE__ */new Set;return t.forEach(t=>{t.items.forEach(n=>{n.type||n.height!==e||s.add(t)})}),s}(t.pages,a),m=n+(a-n)/4;if(c.forEach(t=>{t.items.forEach(t=>{const e=t.height;!t.type&&e>m&&(t.type=e===a?W.H1:W.H2,t.annotation=b,l++)})}),h)Object.keys(s).forEach(e=>{var o=s[e];o.max>n&&t.pages.forEach(t=>{t.items.forEach(t=>{t.type||t.height!==o.max||(t.annotation=b,t.type=W.enumValueOf(e),l++)})})});else{const e=[];t.pages.forEach(t=>{t.items.forEach(t=>{!t.type&&t.height>n&&!i(t.text())&&(e.includes(t.height)||e.push(t.height))})}),e.sort((t,e)=>e-t),e.forEach((e,s)=>{if(s+2<=6){const n=W.headlineByLevel(2+s);t.pages.forEach(t=>{t.items.forEach(t=>{t.type||t.height!==e||i(t.text())||(l++,t.annotation=b,t.type=n)})})}})}var u=1;if(t.pages.forEach(t=>{t.items.forEach(t=>{t.type&&t.type.headline&&(u=Math.max(u,t.type.headlineLevel))})}),u<6){const e=W.headlineByLevel(u+1);t.pages.forEach(t=>{var s;t.items.forEach(t=>{!t.type&&t.height===n&&t.font!==r&&(!s||s.y<t.y||s.type&&s.type.headline||s.y-t.y>2*o)&&t.text()===t.text().toUpperCase()&&(l++,t.annotation=b,t.type=e),s=t})})}return new I({...t,messages:["Detected "+l+" headlines."]})}};var et=class extends f{items;constructor(t){super(t),this.items=[],t.items&&t.items.forEach(t=>this.addItem(t))}addItem(t){if(this.type&&t.type&&this.type!==t.type)throw new Error(`Adding item of type ${t.type.name} to block of type ${this.type.name}`);this.type||(this.type=t.type),t.parsedElements&&(this.parsedElements?this.parsedElements.add(t.parsedElements):this.parsedElements=t.parsedElements);const e=new k({...t});e.type=null,this.items.push(e)}},st=class t extends w{constructor(e){if(super(e,et.name),this.constructor===t)throw new TypeError("Can not construct abstract class.")}completeTransform(t){return t.messages=[],t.pages.forEach(t=>{t.items=t.items.filter(t=>!t.annotation||t.annotation!==T),t.items.forEach(t=>t.annotation=null)}),t}},nt=class extends st{constructor(){super("Gather Blocks")}transform(t){const{mostUsedDistance:e}=t.globals;var s=0,n=0;return t.pages.map(t=>{n+=t.items.length;const o=[];var r=new et({});const a=()=>{r.items.length>1&&(r.annotation=b),o.push(r),r=new et({}),s++};var i=function(t){var e=999;return t.forEach(t=>{e=Math.min(e,t.x)}),999===e?null:e}(t.items);t.items.forEach(t=>{r.items.length>0&&function(t,e,s,n){if(t.type&&t.type.mergeFollowingNonTypedItems&&!e.type)return!1;const o=t.items[t.items.length-1],r=function(t,e,s,n){const o=t.y-e.y;if(o<0-n/2)return!0;var r=n+1;t.x>s&&e.x>s&&(r=n+n/2);return o>r}(o,e,s,n);if(t.type&&t.type.mergeFollowingNonTypedItemsWithSmallDistance&&!e.type&&!r)return!1;if(e.type!==t.type)return!0;return e.type?!e.type.mergeToBlock:r}(r,t,i,e)&&a(),r.addItem(t)}),r.items.length>0&&a(),t.items=o}),new I({...t,messages:["Gathered "+s+" blocks out of "+n+" line items"]})}};var ot=class extends st{constructor(){super("$1")}transform(t){const e=t.globals.mostUsedHeight??0;var s=0;return t.pages.forEach(t=>{var n=function(t){var e=999;return t.forEach(t=>{t.items.forEach(t=>{e=Math.min(e,t.x)})}),999===e?null:e}(t.items);t.items.forEach(t=>{!t.type&&function(t,e,s){if(0===e.length)return!1;if(1===e.length)return e[0].x>t&&e[0].height<=s+1;for(var n of e)if(n.x===t)return!1;return!0}(n,t.items,e)&&(t.annotation=b,t.type=W.CODE,s++)})}),new I({...t,messages:["Detected "+s+" code/quote items."]})}};var rt=class extends st{constructor(){super("Level Lists")}transform(t){var e=0,s=0;return t.pages.forEach(t=>{t.items.filter(t=>t.type===W.LIST).forEach(t=>{var n,o=0;const r={};var a=!1;t.items.forEach(t=>{n?t.x>n?(o++,r[t.x]=o):t.x<n&&(o=r[t.x]):r[t.x]=0,o>0&&(t.words=[new S({string:" ".repeat(3*o)})].concat(t.words),a=!0),n=t.x}),e++,a?(s++,t.annotation=L):t.annotation=v})}),new I({...t,messages:["Modified "+s+" / "+e+" list blocks."]})}},at=class extends w{constructor(){super("To Text Blocks","TextBlock")}transform(t){return t.pages.forEach(t=>{const e=[];t.items.forEach(t=>{const s=t.type?t.type.name:"Unknown";e.push({category:s,text:W.blockToText(t)})}),t.items=e}),new I({...t})}},it=class extends w{constructor(){super("To HTML","String")}transform(t){return t.pages.forEach(t=>{var e="";t.items.forEach(t=>{let s;s="TOC"===t.category?t.text:t.text.replace(/(\r\n|\n|\r)/gm,"\n"),"LIST"!==t.category&&(s=s.split("- ").join("")),"CODE"===t.category&&(s=s.split("<code>").join("").split("</code>").join("")),e+=`<p>${s}</p>\n\n`}),t.items=[e]}),new I({...t})}};async function ht(t,e={}){const{addPageNumbers:s=!1,addCitation:n=!0,liteParseOptions:o={}}=e,r="string"==typeof t?await y(t,{responseType:"arraybuffer",timeout:10}):t;let a;try{({LiteParse:a}=await(import("@llamaindex/liteparse")))}catch(u){return{error:`method: 'liteparse' requires the optional @llamaindex/liteparse dependency (Node.js only): ${u.message}`}}const i=new a({quiet:!0,ocrEnabled:!1,ocrFailureFatal:!1,...o});let h;try{h=await i.parse(new Uint8Array(r))}catch(u){return{error:u.message}}const l=h.pages.reduce((t,e)=>{const n=e.text.split(/\n{2,}/).filter(t=>t.trim().length>0).map(t=>{return(e=t,e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")).replace(/\n/g,"<br/>");var e}).join("</p><p>");return t+`<p id="page-${e.pageNum}">${s?` [${e.pageNum}] `:""}${n}</p>`},"");let c,m;return n&&(m=h.creator||h.producer,c=h.pages[0]?.text.split("\n").find(t=>t.trim().length>0)),{author:m,title:c,html:l,format:"pdf"}}async function lt(t,e={}){const s="string"==typeof t?await y(t,{responseType:"arraybuffer",timeout:10}):t,{LiteParse:n}=await(import("@llamaindex/liteparse")),o=await new n({quiet:!0,...e.liteParseOptions}).isComplex(new Uint8Array(s));return{needsOcr:o.some(t=>t.needsOcr),pages:o,reasons:[...new Set(o.flatMap(t=>t.reasons))]}}async function ct(t,e={}){if("liteparse"===e.method){const{method:s,...n}=e;return ht(t,n)}var{addPageNumbers:s=!1,addCitation:n=!0}=e,o="string"==typeof t?await y(t,{responseType:"arraybuffer",timeout:10}):t;let r;try{let{resolvePDFJS:t}=await(import("https://cdn.jsdelivr.net/npm/pdfjs-serverless@1.1.0/+esm"));const{getDocument:e}=await t();r=await e({data:new Uint8Array(o),useSystemFonts:!0,verbosity:0}).promise}catch(T){return{error:T.message}}const a=[...Array(r.numPages).keys()].map(t=>new g({index:t}));let i,h={};for(let p=1;p<=r.numPages;p++){const t=await r.getPage(p),e=await t.getTextContent();if(!(Object.keys(h).length<10)){i=u(h);break}h=m(h,t.pageNumber-1,e.items)}let l=i?i.pageNum:0;for(let m=1;m<=r.numPages;m++){const t=await r.getPage(m);await t.getOperatorList();const e=t.getViewport({scale:1});let s=await t.getTextContent();i&&t.pageIndex>=i.pageIndex&&(s=p(s,l),l++);const n=s.items.map(t=>{const s=[1,0,0,1,0,0];for(let r=0;r<6;r++)s[r]+=t.transform[r]*e.transform[r%2?3:0],r%2&&(s[r+1]+=t.transform[r]*e.transform[1]);const n=Math.sqrt(s[2]*s[2]+s[3]*s[3]),o=t.height/n;return new d({x:Math.round(t.transform[4]),y:Math.round(t.transform[5]),width:Math.round(t.width),height:Math.round(o<=1?t.height:o),text:t.str,font:t.fontName})});a[t.pageNumber-1].items=n}var c=new I({pages:a});let f;[new U,new q,new R,new V,new Q,new tt,new Z,new nt,new ot,new rt,new at,new it].forEach(t=>{f&&(c=f.completeTransform(c)),c=t.transform(c),f=t});var w=c.pages.reduce((t,e,n)=>t+`<p id="page-${n+1}">${s?` [${n+1}] `:""}${e.items.join('</p><p id="page-'+n+'">')}</p>`,"");if(n){var{Author:x,Title:E}=(await r.getMetadata()).info;E=w.slice(0,400).match(/<h[0-9]>(.*?)<\/h[0-9]>/)?.[1]||E}return{author:x,title:E,html:w,format:"pdf"}}export{ct as convertPDFToHTML,ht as convertPDFToHTMLWithLiteParse,lt as detectPdfNeedsOcr};
|
|
1
|
+
function t(t){for(;32===t.charCodeAt(0);)t=t.substring(1,t.length);return t}function e(t){for(;32===t.charCodeAt(t.length-1);)t=t.substring(0,t.length-1);return t}function s(t){return t>=48&&t<=57}function n(t){for(var e=0;e<t.length;e++)if(!s(t.charCodeAt(e)))return!1;return!0}function o(t,e){const s=e.charCodeAt(0);for(var n=0;n<t.length;n++)if(t.charCodeAt(n)!==s)return!1;return!0}function r(t){return function(t){const e=[];for(var s=0;s<t.length;s++)e.push(t.charCodeAt(s));return e}(t=t.toUpperCase()).filter(t=>32!==t&&9!==t&&46!==t)}function a(t){if(t.length>1)return!1;const e=t.charAt(0);return"-"===e||"•"===e||"–"===e}function i(t){return/^[\s]*[-•–][\s].*$/g.test(t)}function h(t){return t.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}function l(t,e){const s=new Set(t.toUpperCase().split(" ")),n=new Set(e.toUpperCase().split(" "));return new Set([...s].filter(t=>n.has(t))).size/Math.max(s.size,n.size)}var c=(t,e,s)=>Math.floor(t/e*s),m=(s,o,r)=>{for(const{str:a}of s){const s=e(t(a));n(s)&&(o[r]||(o[r]=[]),o[r].push(Number(s)))}return o},u=(t,e,s)=>{const n=c(1,6,s.length),o=c(5,6,s.length),r=m(s.slice(0,n),t,e);return m(s.slice(o),r,e)},p=t=>{let e=0;const s=Object.keys(t);if(0!==s.length&&1!==s.length)for(let n=0;n<s.length-1;n++){const o=t[s[n]],r=t[s[n+1]],a=e;for(let t=0;t<o.length&&e<2;t++)for(let a=0;a<r.length&&e<2;a++){const i=Number(s[n+1])-Number(s[n]);(o[t]+1===r[a]||i>1&&o[t]+i===r[a])&&e++}let i=n>0?Object.entries(t)[n-1]:Object.entries(t)[n];if(a===e)e=0,i=Object.entries(t)[n];else if(e>=2)return{pageIndex:Number(i[0]),pageNum:i[1][0]}}},f=(t,e)=>{const s={items:[...t.items]},n=c(1,6,s.items.length),o=c(5,6,s.items.length);return s.items=s.items.filter((t,r)=>{const a=r>0&&r<n,i=r>o&&r<s.items.length;return a||i?Number(t.str)!==Number(e):t}),s},d=class t{type;annotation;parsedElements;constructor(e){if(this.constructor===t)throw new TypeError("Can not construct abstract class.");this.type=e.type??null,this.annotation=e.annotation??null,this.parsedElements=e.parsedElements??null}},g=class extends d{x;y;width;height;text;font;lineFormat;unopenedFormat;unclosedFormat;constructor(t){super(t),this.x=t.x,this.y=t.y,this.width=t.width,this.height=t.height,this.text=t.text,this.font=t.font,this.lineFormat=t.lineFormat??null,this.unopenedFormat=t.unopenedFormat??null,this.unclosedFormat=t.unclosedFormat??null}},y=class{index;items;constructor(t){this.index=t.index,this.items=t.items||[]}};async function w(t,e={}){const s=e.timeout?1e3*e.timeout:1e4,n=new AbortController,o=setTimeout(()=>n.abort(),s);try{const s=await fetch(t,{signal:n.signal});if(clearTimeout(o),!s.ok)throw new Error(`HTTP ${s.status}`);return"arraybuffer"===e.responseType?await s.arrayBuffer():await s.text()}catch(r){throw clearTimeout(o),r}}var x=class t{name;itemType;constructor(e,s){if(this.constructor===t)throw new TypeError("Can not construct abstract class.");if(this.transform===t.prototype.transform)throw new TypeError("Please implement abstract method 'transform()'.");this.name=e,this.itemType=s}transform(t){throw new TypeError("Do not call abstract method foo from child.")}completeTransform(t){return t.messages=[],t}},E=class{category;color;constructor(t){this.category=t.category,this.color=t.color}},T=new E({category:"Added",color:"green"}),v=new E({category:"Removed",color:"red"}),b=new E({category:"Unchanged",color:"brown"}),L=new E({category:"Detected",color:"green"}),O=new E({category:"Modified",color:"green"}),I=class t extends x{constructor(e){if(super(e,g.name),this.constructor===t)throw new TypeError("Can not construct abstract class.")}completeTransform(t){return t.messages=[],t.pages.forEach(t=>{t.items=t.items.filter(t=>!t.annotation||t.annotation!==v),t.items.forEach(t=>t.annotation=null)}),t}},S=class{pages;globals;messages;constructor(t){this.pages=t.pages||[],this.globals=t.globals||{},this.messages=t.messages||[]}},k=class{string;type;format;constructor(t){this.string=t.string,this.type=t.type??null,this.format=t.format??null}},C=class extends d{x;y;width;height;words;constructor(t){super(t),this.x=t.x??0,this.y=t.y??0,this.width=t.width??0,this.height=t.height??0,this.words=t.words||[],t.text&&!t.words&&(this.words=t.text.split(" ").filter(t=>t.trim().length>0).map(t=>new k({string:t})))}text(){return this.wordStrings().join(" ")}wordStrings(){return this.words.map(t=>t.string)}},F=class t{results;stash;constructor(){if(this.constructor===t)throw new TypeError("Can not construct abstract class.");this.results=[],this.stash=[]}consumeAll(t){t.forEach(t=>this.consume(t))}consume(t){this.shouldStash(t)?(this.matchesStash(t)||this.flushStash(),this.pushOnStash(t)):(this.stash.length>0&&this.flushStash(),this.results.push(t))}pushOnStash(t){this.onPushOnStash(t),this.stash.push(t)}complete(){return this.stash.length>0&&this.flushStash(),this.results}matchesStash(t){if(0===this.stash.length)return!0;const e=this.stash[this.stash.length-1];return this.doMatchesStash(e,t)}flushStash(){this.stash.length>0&&(this.doFlushStash(this.stash,this.results),this.stash=[])}onPushOnStash(t){}shouldStash(t){throw new TypeError(" Do not call abstract method foo from child."+t)}doMatchesStash(t,e){throw new TypeError(" Do not call abstract method foo from child."+t+e)}doFlushStash(t,e){throw new TypeError(" Do not call abstract method foo from child."+t+e)}},N=class{footnoteLinks;footnotes;containLinks;formattedWords;constructor(t){this.footnoteLinks=t.footnoteLinks||[],this.footnotes=t.footnotes||[],this.containLinks=t.containLinks??!1,this.formattedWords=t.formattedWords??0}add(t){this.footnoteLinks=this.footnoteLinks.concat(t.footnoteLinks),this.footnotes=this.footnotes.concat(t.footnotes),this.containLinks=this.containLinks||t.containLinks,this.formattedWords+=t.formattedWords}};function D(t){t.sort((t,e)=>t.x-e.x)}var H={BOLD:{name:"BOLD",startSymbol:"<strong>",endSymbol:"</strong>"},OBLIQUE:{name:"OBLIQUE",startSymbol:"<em>",endSymbol:"</em>"},BOLD_OBLIQUE:{name:"BOLD_OBLIQUE",startSymbol:"<strong><em>",endSymbol:"</em></strong>"}},M={LINK:{name:"LINK",toText:t=>`<a href="${t}">${t}</a>`},FOOTNOTE_LINK:{name:"FOOTNOTE_LINK",attachWithoutWhitespace:!0,plainTextFormat:!0,toText:t=>`<sup><a href="#${t}">${t}</a></sup>`},FOOTNOTE:{name:"FOOTNOTE",toText:t=>`<p id="${t}">^${t}</p>`}},U=class{fontToFormats;constructor(t){this.fontToFormats=t}compact(t){D(t);const e=new B(this.fontToFormats);e.consumeAll(t.map(t=>new g({...t})));const s=e.complete();var n=0,o=0;return t.forEach(t=>{n=Math.max(n,t.height),o+=t.width}),new C({x:t[0].x,y:t[0].y,height:n,width:o,words:s,parsedElements:new N({footnoteLinks:e.footnoteLinks,footnotes:e.footnotes,containLinks:e.containLinks,formattedWords:e.formattedWords})})}},B=class extends F{fontToFormats;footnoteLinks;footnotes;formattedWords;containLinks;stashedNumber;firstY;currentItem;constructor(t){super(),this.fontToFormats=t,this.footnoteLinks=[],this.footnotes=[],this.formattedWords=0,this.containLinks=!1,this.stashedNumber=!1,this.currentItem=null}shouldStash(t){return this.firstY||(this.firstY=t.y),this.currentItem=t,!0}onPushOnStash(t){this.stashedNumber=n(t.text.trim())}doMatchesStash(t,e){if(this.fontToFormats.get(t.font)!==this.fontToFormats.get(e.font))return!1;const s=n(e.text.trim());return this.stashedNumber===s}doFlushStash(t,e){if(this.stashedNumber){const s=t.map(t=>t.text).join("").trim();t[0].y>this.firstY?(e.push(new k({string:`${s}`,type:M.FOOTNOTE_LINK})),this.footnoteLinks.push(parseInt(s))):this.currentItem&&this.currentItem.y<t[0].y?(e.push(new k({string:`${s}`,type:M.FOOTNOTE})),this.footnotes.push(s)):this.copyStashItemsAsText(t,e)}else this.copyStashItemsAsText(t,e)}copyStashItemsAsText(t,e){const s=this.fontToFormats.get(t[0].font);e.push(...this.itemsToWords(t,s))}itemsToWords(t,e){const s=(n=t,o="",r=null,n.forEach(t=>{var e=t.text;o.endsWith(" ")||e.startsWith(" ")||(r?t.x-r.x-r.width>5&&(o+=" "):a(t.text)&&(e+=" ")),o+=e,r=t}),o).split(" ");var n,o,r;const i=e?H[e]:null;return s.filter(t=>t.trim().length>0).map(t=>{var e=null;return t.startsWith("http:")?(this.containLinks=!0,e=M.LINK):t.startsWith("www.")&&(this.containLinks=!0,t=`http://${t}`,e=M.LINK),i&&this.formattedWords++,new k({string:t,type:e,format:i})})}};var A=class extends I{fontMap;constructor(t){super("Calculate Global Stats"),this.fontMap=t}transform(t){const e={},s={};var n,o=0;t.pages.forEach(t=>{t.items.forEach(t=>{t.height&&(e[t.height]=e[t.height]?e[t.height]+1:1,s[t.font]=s[t.font]?s[t.font]+1:1,t.height>o&&(o=t.height,n=t.font))})});const r=parseInt($(e)),a=$(s),i={};t.pages.forEach(t=>{var e;t.items.forEach(t=>{if(t.height===r&&t.text.trim().length>0){if(e&&t.y!==e.y){const s=e.y-t.y;s>0&&(i[s]=i[s]?i[s]+1:1)}e=t}else e=null})});const h=parseInt($(i)),l=[],c=/* @__PURE__ */new Map;this.fontMap?.forEach(function(t,e){l.push(e+" = "+t.name);const s=t.name.toLowerCase();var o=null;e===a?o=null:s.includes("bold")&&(s.includes("oblique")||s.includes("italic"))?o=H.BOLD_OBLIQUE:s.includes("bold")?o=H.BOLD:s.includes("oblique")||s.includes("italic")?o=H.OBLIQUE:s===n&&(o=H.BOLD),o&&c.set(e,o.name)}),l.sort();const m=t.pages.map(t=>({...t,items:t.items.map(t=>({...t}))}));return new S({...t,pages:m,globals:{mostUsedHeight:r,mostUsedFont:a,mostUsedDistance:h,maxHeight:o,maxHeightFont:n,fontToFormats:c},messages:["Items per height: "+JSON.stringify(e),"Items per font: "+JSON.stringify(s),"Items per distance: "+JSON.stringify(i),"Fonts:"+JSON.stringify(l)]})}};function $(t){var e=0,s="";return Object.keys(t).map(n=>{(!s||t[n]>e)&&(e=t[n],s=n)}),s}var P=class t extends x{constructor(e){if(super(e,C.name),this.constructor===t)throw new TypeError("Can not construct abstract class.")}completeTransform(t){return t.messages=[],t.pages.forEach(t=>{t.items=t.items.filter(t=>!t.annotation||t.annotation!==v),t.items.forEach(t=>t.annotation=null)}),t}},W=class{mostUsedDistance;constructor(t){this.mostUsedDistance=t.mostUsedDistance||12}group(t){const e=[];var s=[];return t.forEach(t=>{s.length>0&&Math.abs(s[0].y-t.y)>=this.mostUsedDistance/2&&(e.push(s),s=[]),s.push(t)}),e.push(s),e.forEach(t=>{D(t)}),e}},j={H1:{name:"H1",headline:!0,headlineLevel:1,toText:t=>"<h1>"+q(t.items,!0)+"</h1>"},H2:{name:"H2",headline:!0,headlineLevel:2,toText:t=>"<h2>"+q(t.items,!0)+"</h2>"},H3:{name:"H3",headline:!0,headlineLevel:3,toText:t=>"<h3>"+q(t.items,!0)+"</h3>"},H4:{name:"H4",headline:!0,headlineLevel:4,toText:t=>"<h4>"+q(t.items,!0)+"</h4>"},H5:{name:"H5",headline:!0,headlineLevel:5,toText:t=>"<h5>"+q(t.items,!0)+"</h5>"},H6:{name:"H6",headline:!0,headlineLevel:6,toText:t=>"<h6>"+q(t.items,!0)+"</h6>"},TOC:{name:"TOC",mergeToBlock:!0,toText:t=>q(t.items,!0)},FOOTNOTES:{name:"FOOTNOTES",mergeToBlock:!0,mergeFollowingNonTypedItems:!0,toText:t=>"<p>"+q(t.items,!1)+"</p>"},CODE:{name:"CODE",mergeToBlock:!0,toText:t=>"<code>"+q(t.items,!0)+"</code>"},LIST:{name:"LIST",mergeToBlock:!1,mergeFollowingNonTypedItemsWithSmallDistance:!0,toText:t=>"<ul>\n"+q(t.items,!1)+"</ul>"},PARAGRAPH:{name:"PARAGRAPH",toText:t=>"<p>"+q(t.items,!1)+"</p>"}};function q(t,e){var s,n="";const o=()=>{n+=s.endSymbol,s=null};return t.forEach((r,a)=>{var i;r&&(r.words.forEach((t,r)=>{const a=t.type,i=t.format;var h;!s||i&&i===s||o(),r>0&&(!a||!a.attachWithoutWhitespace)&&(1!==(h=t.string).length||"."!==h[0]&&"!"!==h[0]&&"?"!==h[0])&&(n+=" "),!i||s||e||(n+=(s=i).startSymbol),!a||e&&!a.plainTextFormat?n+=t.string:n+=a.toText(t.string)}),!s||a!==t.length-1&&(0===(i=t[a+1]).words.length?null:i.words[0].format)===s||o(),n+="\n")}),n}j.enumValueOf=function(t){return j[t]},j.isHeadline=function(t){return t&&2===t.name.length&&"H"===t.name[0]},j.blockToText=function(t){return t.type?t.type.toText(t):q(t.items,!1)},j.headlineByLevel=function(t){return 1===t?j.H1:2===t?j.H2:3===t?j.H3:4===t?j.H4:5===t?j.H5:(t>6&&console.warn("Unsupported headline level: "+t+" (supported are 1-6), defaulting to level 6"),j.H6)};var Y=class extends P{constructor(){super("Compact To Lines")}transform(t){const{mostUsedDistance:e,fontToFormats:s}=t.globals,n=[],o=[];var r=0,a=0;const i=new W({mostUsedDistance:e}),h=new U(s);return t.pages.forEach(t=>{if(t.items.length>0){const e=[];i.group(t.items).forEach(s=>{const i=h.compact(s);if(s.length>1&&(i.annotation=T,s.forEach(t=>{t.annotation=v,e.push(new C({...t}))})),0===i.words.length&&(i.annotation=v),e.push(i),i.parsedElements.formattedWords&&(a+=i.parsedElements.formattedWords),i.parsedElements.containLinks&&r++,i.parsedElements.footnoteLinks.length>0){const e=i.parsedElements.footnoteLinks.map(e=>({footnoteLink:e,page:t.index+1}));o.push.apply(o,e)}if(i.parsedElements.footnotes.length>0){i.type=j.FOOTNOTES;const e=i.parsedElements.footnotes.map(e=>({footnote:e,page:t.index+1}));n.push.apply(n,e)}}),t.items=e}}),new S({...t,messages:["Detected "+a+" formatted words","Found "+r+" links","Detected "+o.length+" footnotes links","Detected "+n.length+" footnotes"]})}};function R(t){var e=0;if(0===t.trim().length)return e;for(var n=0;n<t.length;n++){const o=t.charCodeAt(n);s(o)||32===o||160===o||(e=(e<<5)-e+o,e|=0)}return e}var V=class extends P{constructor(){super("Remove Repetitive Elements")}transform(t){const e=[],s={},n={};t.pages.forEach(t=>{const o=t.items.reduce((t,e)=>(e.y<t.minY?(t.minElements=[e],t.minY=e.y):e.y===t.minY&&t.minElements.push(e),e.y>t.maxY?(t.maxElements=[e],t.maxY=e.y):e.y===t.maxY&&t.maxElements.push(e),t),{minY:999,maxY:0,minElements:[],maxElements:[]}),r=R(o.minElements.reduce((t,e)=>t+e.text().toUpperCase(),"")),a=R(o.maxElements.reduce((t,e)=>t+e.text().toUpperCase(),""));e.push({minElements:o.minElements,maxElements:o.maxElements,minLineHash:r,maxLineHash:a}),s[r]=s[r]?s[r]+1:1,n[a]=n[a]?n[a]+1:1});var o=0,r=0;return t.pages.forEach((a,i)=>{s[e[i].minLineHash]>=Math.max(3,2*t.pages.length/3)&&(e[i].minElements.forEach(t=>{t.annotation=v}),r++),n[e[i].maxLineHash]>=Math.max(3,2*t.pages.length/3)&&(e[i].maxElements.forEach(t=>{t.annotation=v}),o++)}),new S({...t,messages:["Removed Header: "+o,"Removed Footers: "+r]})}},K=class extends P{constructor(){super("Vertical to Horizontal Text")}transform(t){var e=0;return t.pages.forEach(t=>{const s=new J;s.consumeAll(t.items),t.items=s.complete(),e+=s.foundVerticals}),new S({...t,messages:["Converted "+e+" verticals"]})}},J=class extends F{foundVerticals;constructor(){super(),this.foundVerticals=0}shouldStash(t){return 1===t.words.length&&1===t.words[0].string.length}doMatchesStash(t,e){return t.y-e.y>5&&t.words[0].type===e.words[0].type}doFlushStash(t,e){if(t.length>5){var s=[],n=999,o=0,r=0,a=0;t.forEach(t=>{t.annotation=v,e.push(t),s.push(t.words[0]),n=Math.min(n,t.x),o=Math.max(o,t.y),r+=t.width,a=Math.max(a,t.height)}),e.push(new C({...t[0],x:n,y:o,width:r,height:a,words:s,annotation:T})),this.foundVerticals++}else e.push(...t)}},Q=class{headlineCharCodes;stackedLineItems;stackedChars;constructor(t){this.headlineCharCodes=r(t.headline),this.stackedLineItems=[],this.stackedChars=0}consume(t){const e=r(t.text());if(this.matchAll(e)){if(this.stackedLineItems.push(t),this.stackedChars+=e.length,this.stackedChars===this.headlineCharCodes.length)return this.stackedLineItems}else this.stackedChars>0&&(this.stackedChars=0,this.stackedLineItems=[],this.consume(t));return null}matchAll(t){for(var e=0;e<t.length;e++){const s=this.headlineCharCodes[this.stackedChars+e];if(t[e]!==s)return!1}return!0}},_=class extends P{constructor(){super("Detect TOC")}transform(t){const e=[],r=Math.min(20,t.pages.length),a=new X;var i,h,c=[];t.pages.slice(0,r).forEach(t=>{var r=0;const l=/* @__PURE__ */new Set,m=[];var u,p;if(t.items.filter(t=>t.words.includes(t=>o(t.string,"."))).forEach(t=>{var e=t.words.filter(t=>!o(t.string,"."));const a=[];for(;e.length>0&&n(e[e.length-1].string);){const t=e.pop();a.unshift(t.string)}if(0===a.length&&e.length>0){const t=e[e.length-1];for(;s(t.string.charCodeAt(t.string.length-1));)a.unshift(t.string.charAt(t.string.length-1)),t.string=t.string.substring(0,t.string.length-1)}var i=a.length>0;i?(i=!0,u&&(e.push(...u),u=null),m.push(new Z({pageNumber:parseInt(a.join("")),lineItem:new C({...t,words:e})})),r++):h?(u&&l.add(p),u=e,p=t):h=t}),100*r/t.items.length>75){e.push(t.index+1),i=t,a.levelPageItems(m),c.push(...m);const s=[];t.items.forEach(t=>{l.has(t)||(t.annotation=v),s.push(t),t===h&&s.push(new C({...t,type:j.H2,annotation:T}))}),t.items=s}else h=null});var m=c.length;const u=[],p=[],f={};if(e.length>0){c.forEach(t=>{i.items.push(new C({words:[new k({string:" ".repeat(3*t.level)+"-"})].concat(t.lineItem.words),type:j.TOC,annotation:T}))});const e=function(t,e){for(var s of e){const e=z(t,s.lineItem.text());if(e)return e.index-s.pageNumber}return null}(t.pages.filter(t=>t.index>i.index),c);c.forEach(s=>{var n,o=t.pages[s.pageNumber+e];o&&((n=G(o,s.lineItem.text()))||(o=t.pages[s.pageNumber+e+1])&&(n=G(o,s.lineItem.text()))),n?function(t,e,s,n){s.headlineItems.forEach(t=>t.annotation=v);const o=j.headlineByLevel(e.level+2),r=s.headlineItems.reduce((t,e)=>Math.max(t,e.height),0);t.items.splice(s.lineIndex+1,0,new C({...s.headlineItems[0],words:e.lineItem.words,height:r,type:o,annotation:T}));var a=n[o.name];a?(a.min=Math.min(a.min,r),a.max=Math.max(a.max,r)):(a={min:r,max:r},n[o.name]=a)}(o,s,n,f):u.push(s)});var d=i.index+2,g=[];const s=e=>{g.length>0&&(g.forEach(s=>{const n=j.headlineByLevel(s.level+2),o=f[n.name];if(o){const[r,a]=function(t,e,s,n,o){const r=e.lineItem.text().toUpperCase();for(var a=n;a<=o;a++){const e=t[a-1];if(e){const t=e.items.findIndex(t=>!t.type&&!t.annotation&&t.height>=s.min&&t.height<=s.max&&l(r,t.text())>=.5);if(t>-1)return[a-1,t]}}return[-1,-1]}(t.pages,s,o,d,e);if(a>-1){const e=t.pages[r];e.items[a].annotation=v,e.items.splice(a+1,0,new C({...s.lineItem,type:n,annotation:T})),p.push(s)}}}),g=[])};u.length>0&&(c.forEach(t=>{u.includes(t)?g.push(t):(s(t.pageNumber),d=t.pageNumber)}),g.length>0&&s(t.pages.length))}const y=[];return y.push("Detected "+e.length+" table of content pages"),e.length>0&&(y.push("TOC headline heights: "+JSON.stringify(f)),y.push("Found TOC headlines: "+(m-u.length+p.length)+"/"+m)),u.length>0&&(y.push("Found TOC headlines (by size): "+p.map(t=>t.lineItem.text())),y.push("Missing TOC headlines: "+u.filter(t=>!p.includes(t)).map(t=>t.lineItem.text()+"=>"+t.pageNumber))),new S({...t,globals:{...t.globals,tocPages:e,headlineTypeToHeightRange:f},messages:y})}};function z(t,e){for(var s of t)if(G(s,e))return s;return null}function G(t,e){const s=new Q({headline:e});var n=0;for(var o of t.items){const t=s.consume(o);if(t)return{lineIndex:n,headlineItems:t};n++}return null}var X=class{levelByMethod;uniqueFonts;constructor(){this.levelByMethod=null,this.uniqueFonts=[]}levelPageItems(t){if(!this.levelByMethod)if(this.calculateUniqueX(t).length>1)this.levelByMethod=this.levelByXDiff;else{const e=this.calculateUniqueFonts(t);e.length>1?(this.uniqueFonts=e,this.levelByMethod=this.levelByFont):this.levelByMethod=this.levelToZero}this.levelByMethod(t)}levelByXDiff(t){const e=this.calculateUniqueX(t);t.forEach(t=>{t.level=e.indexOf(t.lineItem.x)})}levelByFont(t){t.forEach(t=>{t.level=this.uniqueFonts.indexOf(t.lineItem.font)})}levelToZero(t){t.forEach(t=>{t.level=0})}calculateUniqueX(t){var e=t.reduce(function(t,e){return t.indexOf(e.lineItem.x)<0&&t.push(e.lineItem.x),t},[]);return e.sort((t,e)=>t-e),e}calculateUniqueFonts(t){return t.reduce(function(t,e){return t.indexOf(e.lineItem.font)<0&&t.push(e.lineItem.font),t},[])}},Z=class{lineItem;pageNumber;level;constructor(t){this.lineItem=t.lineItem,this.pageNumber=t.pageNumber,this.level=0}},tt=class extends P{constructor(){super("Detect List Items")}transform(t){var e=0,s=0;return t.pages.forEach(t=>{const n=[];t.items.forEach(t=>{if(n.push(t),!t.type){var o=t.text();if(a(t.words[0].string))if(e++,"-"===t.words[0].string)t.annotation=L,t.type=j.LIST;else{t.annotation=v;const e=t.words.map(t=>new k({...t}));e[0].string="-",n.push(new C({...t,words:e,annotation:T,type:j.LIST}))}else/^[\s]*[\d]*[.][\s].*$/g.test(o)&&(s++,t.annotation=L,t.type=j.LIST)}}),t.items=n}),new S({...t,messages:["Detected "+e+" plain list items.","Detected "+s+" numbered list items."]})}},et=class extends P{constructor(){super("Detect Headers")}transform(t){const{tocPages:e,headlineTypeToHeightRange:s,mostUsedHeight:n,mostUsedDistance:o,mostUsedFont:r,maxHeight:a}=t.globals,h=e.length>0;var l=0;const c=function(t,e){const s=/* @__PURE__ */new Set;return t.forEach(t=>{t.items.forEach(n=>{n.type||n.height!==e||s.add(t)})}),s}(t.pages,a),m=n+(a-n)/4;if(c.forEach(t=>{t.items.forEach(t=>{const e=t.height;!t.type&&e>m&&(t.type=e===a?j.H1:j.H2,t.annotation=L,l++)})}),h)Object.keys(s).forEach(e=>{var o=s[e];o.max>n&&t.pages.forEach(t=>{t.items.forEach(t=>{t.type||t.height!==o.max||(t.annotation=L,t.type=j.enumValueOf(e),l++)})})});else{const e=[];t.pages.forEach(t=>{t.items.forEach(t=>{!t.type&&t.height>n&&!i(t.text())&&(e.includes(t.height)||e.push(t.height))})}),e.sort((t,e)=>e-t),e.forEach((e,s)=>{if(s+2<=6){const n=j.headlineByLevel(2+s);t.pages.forEach(t=>{t.items.forEach(t=>{t.type||t.height!==e||i(t.text())||(l++,t.annotation=L,t.type=n)})})}})}var u=1;if(t.pages.forEach(t=>{t.items.forEach(t=>{t.type&&t.type.headline&&(u=Math.max(u,t.type.headlineLevel))})}),u<6){const e=j.headlineByLevel(u+1);t.pages.forEach(t=>{var s;t.items.forEach(t=>{!t.type&&t.height===n&&t.font!==r&&(!s||s.y<t.y||s.type&&s.type.headline||s.y-t.y>2*o)&&t.text()===t.text().toUpperCase()&&(l++,t.annotation=L,t.type=e),s=t})})}return new S({...t,messages:["Detected "+l+" headlines."]})}};var st=class extends d{items;constructor(t){super(t),this.items=[],t.items&&t.items.forEach(t=>this.addItem(t))}addItem(t){if(this.type&&t.type&&this.type!==t.type)throw new Error(`Adding item of type ${t.type.name} to block of type ${this.type.name}`);this.type||(this.type=t.type),t.parsedElements&&(this.parsedElements?this.parsedElements.add(t.parsedElements):this.parsedElements=t.parsedElements);const e=new C({...t});e.type=null,this.items.push(e)}},nt=class t extends x{constructor(e){if(super(e,st.name),this.constructor===t)throw new TypeError("Can not construct abstract class.")}completeTransform(t){return t.messages=[],t.pages.forEach(t=>{t.items=t.items.filter(t=>!t.annotation||t.annotation!==v),t.items.forEach(t=>t.annotation=null)}),t}},ot=class extends nt{constructor(){super("Gather Blocks")}transform(t){const{mostUsedDistance:e}=t.globals;var s=0,n=0;return t.pages.map(t=>{n+=t.items.length;const o=[];var r=new st({});const a=()=>{r.items.length>1&&(r.annotation=L),o.push(r),r=new st({}),s++};var i=function(t){var e=999;return t.forEach(t=>{e=Math.min(e,t.x)}),999===e?null:e}(t.items);t.items.forEach(t=>{r.items.length>0&&function(t,e,s,n){if(t.type&&t.type.mergeFollowingNonTypedItems&&!e.type)return!1;const o=t.items[t.items.length-1],r=function(t,e,s,n){const o=t.y-e.y;if(o<0-n/2)return!0;var r=n+1;t.x>s&&e.x>s&&(r=n+n/2);return o>r}(o,e,s,n);if(t.type&&t.type.mergeFollowingNonTypedItemsWithSmallDistance&&!e.type&&!r)return!1;if(e.type!==t.type)return!0;return e.type?!e.type.mergeToBlock:r}(r,t,i,e)&&a(),r.addItem(t)}),r.items.length>0&&a(),t.items=o}),new S({...t,messages:["Gathered "+s+" blocks out of "+n+" line items"]})}};var rt=class extends nt{constructor(){super("$1")}transform(t){const e=t.globals.mostUsedHeight??0;var s=0;return t.pages.forEach(t=>{var n=function(t){var e=999;return t.forEach(t=>{t.items.forEach(t=>{e=Math.min(e,t.x)})}),999===e?null:e}(t.items);t.items.forEach(t=>{!t.type&&function(t,e,s){if(0===e.length)return!1;if(1===e.length)return e[0].x>t&&e[0].height<=s+1;for(var n of e)if(n.x===t)return!1;return!0}(n,t.items,e)&&(t.annotation=L,t.type=j.CODE,s++)})}),new S({...t,messages:["Detected "+s+" code/quote items."]})}};var at,it=class extends nt{constructor(){super("Level Lists")}transform(t){var e=0,s=0;return t.pages.forEach(t=>{t.items.filter(t=>t.type===j.LIST).forEach(t=>{var n,o=0;const r={};var a=!1;t.items.forEach(t=>{n?t.x>n?(o++,r[t.x]=o):t.x<n&&(o=r[t.x]):r[t.x]=0,o>0&&(t.words=[new k({string:" ".repeat(3*o)})].concat(t.words),a=!0),n=t.x}),e++,a?(s++,t.annotation=O):t.annotation=b})}),new S({...t,messages:["Modified "+s+" / "+e+" list blocks."]})}},ht=class extends x{constructor(){super("To Text Blocks","TextBlock")}transform(t){return t.pages.forEach(t=>{const e=[];t.items.forEach(t=>{const s=t.type?t.type.name:"Unknown";e.push({category:s,text:j.blockToText(t)})}),t.items=e}),new S({...t})}},lt=class extends x{constructor(){super("To HTML","String")}transform(t){return t.pages.forEach(t=>{var e="";t.items.forEach(t=>{let s;s="TOC"===t.category?t.text:t.text.replace(/(\r\n|\n|\r)/gm,"\n"),"LIST"!==t.category&&(s=s.split("- ").join("")),"CODE"===t.category&&(s=s.split("<code>").join("").split("</code>").join("")),e+=`<p>${s}</p>\n\n`}),t.items=[e]}),new S({...t})}};async function ct(t,e={}){const{addPageNumbers:s=!1,addCitation:n=!0,liteParseOptions:o={}}=e,r="string"==typeof t?await w(t,{responseType:"arraybuffer",timeout:10}):t;let a;try{({LiteParse:a}=await import("@llamaindex/liteparse"))}catch(p){return{error:`method: 'liteparse' requires the optional @llamaindex/liteparse dependency (Node.js only): ${p.message}`}}const i=new a({quiet:!0,ocrEnabled:!1,ocrFailureFatal:!1,...o});let l;try{l=await i.parse(new Uint8Array(r))}catch(p){return{error:p.message}}const c=l.pages.reduce((t,e)=>{const n=e.text.split(/\n{2,}/).filter(t=>t.trim().length>0).map(t=>h(t).replace(/\n/g,"<br/>")).join("</p><p>");return t+`<p id="page-${e.pageNum}">${s?` [${e.pageNum}] `:""}${n}</p>`},"");let m,u;return n&&(u=l.creator||l.producer,m=l.pages[0]?.text.split("\n").find(t=>t.trim().length>0)),{author:u,title:m,html:c,format:"pdf"}}async function mt(t,e={}){const{addPageNumbers:s=!1,addCitation:n=!0,liteParseOptions:o={}}=e,r="string"==typeof t?await w(t,{responseType:"arraybuffer",timeout:10}):t;let a;try{a=await import("@llamaindex/liteparse-wasm"),await async function(t){at||(at=t.default()),await at}(a)}catch(p){return{error:`method: 'liteparse-wasm' requires the optional @llamaindex/liteparse-wasm dependency: ${p.message}`}}const i=new a.LiteParse({quiet:!0,ocrEnabled:!1,ocrFailureFatal:!1,...o});let l;try{l=await i.parse(new Uint8Array(r))}catch(p){return{error:p.message}}const c=l.pages.reduce((t,e)=>{const n=e.text.split(/\n{2,}/).filter(t=>t.trim().length>0).map(t=>h(t).replace(/\n/g,"<br/>")).join("</p><p>");return t+`<p id="page-${e.pageNum}">${s?` [${e.pageNum}] `:""}${n}</p>`},"");let m,u;return n&&(u=l.creator||l.producer,m=l.pages[0]?.text.split("\n").find(t=>t.trim().length>0)),{author:u,title:m,html:c,format:"pdf"}}async function ut(t,e={}){const s="string"==typeof t?await w(t,{responseType:"arraybuffer",timeout:10}):t,{LiteParse:n}=await import("@llamaindex/liteparse"),o=await new n({quiet:!0,...e.liteParseOptions}).isComplex(new Uint8Array(s));return{needsOcr:o.some(t=>t.needsOcr),pages:o,reasons:[...new Set(o.flatMap(t=>t.reasons))]}}async function pt(t,e={}){if("liteparse"===e.method){const{method:s,...n}=e;return ct(t,n)}if("liteparse-wasm"===e.method){const{method:s,...n}=e;return mt(t,n)}var{addPageNumbers:s=!1,addCitation:n=!0}=e,o="string"==typeof t?await w(t,{responseType:"arraybuffer",timeout:10}):t;let r;try{let{resolvePDFJS:t}=await import("https://cdn.jsdelivr.net/npm/pdfjs-serverless@1.1.0/+esm");const{getDocument:e}=await t();r=await e({data:new Uint8Array(o),useSystemFonts:!0,verbosity:0}).promise}catch(T){return{error:T.message}}const a=[...Array(r.numPages).keys()].map(t=>new y({index:t}));let i,h={};for(let f=1;f<=r.numPages;f++){const t=await r.getPage(f),e=await t.getTextContent();if(!(Object.keys(h).length<10)){i=p(h);break}h=u(h,t.pageNumber-1,e.items)}let l=i?i.pageNum:0;for(let u=1;u<=r.numPages;u++){const t=await r.getPage(u);await t.getOperatorList();const e=t.getViewport({scale:1});let s=await t.getTextContent();i&&t.pageIndex>=i.pageIndex&&(s=f(s,l),l++);const n=s.items.map(t=>{const s=[1,0,0,1,0,0];for(let r=0;r<6;r++)s[r]+=t.transform[r]*e.transform[r%2?3:0],r%2&&(s[r+1]+=t.transform[r]*e.transform[1]);const n=Math.sqrt(s[2]*s[2]+s[3]*s[3]),o=t.height/n;return new g({x:Math.round(t.transform[4]),y:Math.round(t.transform[5]),width:Math.round(t.width),height:Math.round(o<=1?t.height:o),text:t.str,font:t.fontName})});a[t.pageNumber-1].items=n}var c=new S({pages:a});let m;[new A,new Y,new V,new K,new _,new et,new tt,new ot,new rt,new it,new ht,new lt].forEach(t=>{m&&(c=m.completeTransform(c)),c=t.transform(c),m=t});var d=c.pages.reduce((t,e,n)=>t+`<p id="page-${n+1}">${s?` [${n+1}] `:""}${e.items.join('</p><p id="page-'+n+'">')}</p>`,"");if(n){var{Author:x,Title:E}=(await r.getMetadata()).info;E=d.slice(0,400).match(/<h[0-9]>(.*?)<\/h[0-9]>/)?.[1]||E}return{author:x,title:E,html:d,format:"pdf"}}export{pt as convertPDFToHTML,ct as convertPDFToHTMLWithLiteParse,mt as convertPDFToHTMLWithLiteParseWasm,ut as detectPdfNeedsOcr};
|
|
@@ -11,4 +11,5 @@ export declare function suffixBeforeWhitespace(string: string, suffix: string):
|
|
|
11
11
|
export declare function isListItemCharacter(string: string): boolean;
|
|
12
12
|
export declare function isListItem(string: string): boolean;
|
|
13
13
|
export declare function isNumberedListItem(string: string): boolean;
|
|
14
|
+
export declare function escapeHtml(text: string): string;
|
|
14
15
|
export declare function wordMatch(string1: string, string2: string): number;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "extract-pdf",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.202",
|
|
4
4
|
"description": "Convert a PDF (URL or ArrayBuffer) into clean HTML with structural tagging — headings, lists, footnotes, code blocks, bold/italic. Works in Node.js, Cloudflare Workers, and browser environments.",
|
|
5
5
|
"author": "vtempest <grokthiscontact@gmail.com>",
|
|
6
6
|
"license": "rights.institute/PROSPER",
|
|
@@ -26,11 +26,10 @@
|
|
|
26
26
|
"test:coverage": "bun test --coverage --coverage-reporter=lcov --coverage-reporter=text",
|
|
27
27
|
"ship": "npm run build && npx standard-version --release-as patch; rm -f CHANGELOG.md; npm publish"
|
|
28
28
|
},
|
|
29
|
-
"dependencies": {
|
|
30
|
-
"grab-url": "^1.6.22"
|
|
31
|
-
},
|
|
29
|
+
"dependencies": {},
|
|
32
30
|
"optionalDependencies": {
|
|
33
|
-
"@llamaindex/liteparse": "^2.10.0"
|
|
31
|
+
"@llamaindex/liteparse": "^2.10.0",
|
|
32
|
+
"@llamaindex/liteparse-wasm": "^2.11.0"
|
|
34
33
|
},
|
|
35
34
|
"devDependencies": {
|
|
36
35
|
"terser": "^5.46.0",
|
package/src/liteparse-to-html.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* and requires the optional `@llamaindex/liteparse` dependency to be installed.
|
|
7
7
|
*/
|
|
8
8
|
import { grab } from "./utils/grab";
|
|
9
|
+
import { escapeHtml } from "./utils/string-functions";
|
|
9
10
|
import type { LiteParseConfig } from "@llamaindex/liteparse";
|
|
10
11
|
|
|
11
12
|
export interface LiteParseHTMLOptions {
|
|
@@ -14,10 +15,6 @@ export interface LiteParseHTMLOptions {
|
|
|
14
15
|
liteParseOptions?: Partial<LiteParseConfig>;
|
|
15
16
|
}
|
|
16
17
|
|
|
17
|
-
function escapeHtml(text: string): string {
|
|
18
|
-
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
19
|
-
}
|
|
20
|
-
|
|
21
18
|
/**
|
|
22
19
|
* Converts a PDF (URL or ArrayBuffer) into HTML using LiteParse's spatial text
|
|
23
20
|
* extraction, mirroring the return shape of `convertPDFToHTML`.
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Alternate `ParseMethod` for convertPDFToHTML that delegates to LiteParse's
|
|
3
|
+
* [WASM build](https://github.com/run-llama/liteparse/blob/main/packages/wasm/README.md)
|
|
4
|
+
* instead of the native napi addon. Unlike `"liteparse"`, this path runs
|
|
5
|
+
* anywhere WebAssembly does — browsers, Cloudflare Workers, and Node.js — and
|
|
6
|
+
* requires the optional `@llamaindex/liteparse-wasm` dependency to be
|
|
7
|
+
* installed. OCR is not built in; pass `liteParseOptions.ocrEngine` (e.g.
|
|
8
|
+
* backed by tesseract-js) to enable it.
|
|
9
|
+
*/
|
|
10
|
+
import { grab } from "./utils/grab";
|
|
11
|
+
import { escapeHtml } from "./utils/string-functions";
|
|
12
|
+
import type { LiteParseInit } from "@llamaindex/liteparse-wasm";
|
|
13
|
+
|
|
14
|
+
export interface LiteParseWasmHTMLOptions {
|
|
15
|
+
addPageNumbers?: boolean;
|
|
16
|
+
addCitation?: boolean;
|
|
17
|
+
liteParseOptions?: Partial<LiteParseInit>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// wasm-bindgen's `init()` locates and instantiates the .wasm binary itself
|
|
21
|
+
// (relative to the package, via fetch in the browser or Node.js's file
|
|
22
|
+
// loader); it only needs to run once per process, so the promise is cached
|
|
23
|
+
// at module scope and reused by every call.
|
|
24
|
+
let wasmInitPromise: Promise<unknown> | undefined;
|
|
25
|
+
|
|
26
|
+
async function ensureWasmInit(
|
|
27
|
+
liteParseWasm: typeof import("@llamaindex/liteparse-wasm"),
|
|
28
|
+
): Promise<void> {
|
|
29
|
+
if (!wasmInitPromise) {
|
|
30
|
+
wasmInitPromise = liteParseWasm.default();
|
|
31
|
+
}
|
|
32
|
+
await wasmInitPromise;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Converts a PDF (URL or ArrayBuffer) into HTML using LiteParse's WASM build,
|
|
37
|
+
* mirroring the return shape of `convertPDFToHTML`.
|
|
38
|
+
* @param pdfURLOrBuffer - URL to a PDF file or buffer from fs.readFile
|
|
39
|
+
* @param options.addPageNumbers default=false - Adds `[n]` markers at each page boundary
|
|
40
|
+
* @param options.addCitation default=true - Populates `title`/`author` from PDF metadata
|
|
41
|
+
* @param options.liteParseOptions - Passed through to the `LiteParse` constructor;
|
|
42
|
+
* defaults to `{ ocrEnabled: false, ocrFailureFatal: false }` (use detectPdfNeedsOcr
|
|
43
|
+
* to decide when a document is worth re-parsing with `ocrEnabled: true`, or pass
|
|
44
|
+
* `ocrEngine` to run OCR in-process, e.g. via tesseract-js)
|
|
45
|
+
* @returns `{ html, title, author, format: "pdf" }`, or `{ error }` on failure
|
|
46
|
+
* @category Extract
|
|
47
|
+
*/
|
|
48
|
+
export async function convertPDFToHTMLWithLiteParseWasm(
|
|
49
|
+
pdfURLOrBuffer: any,
|
|
50
|
+
options: LiteParseWasmHTMLOptions = {},
|
|
51
|
+
) {
|
|
52
|
+
const { addPageNumbers = false, addCitation = true, liteParseOptions = {} } = options;
|
|
53
|
+
|
|
54
|
+
const buffer =
|
|
55
|
+
typeof pdfURLOrBuffer === "string"
|
|
56
|
+
? await grab(pdfURLOrBuffer, { responseType: "arraybuffer", timeout: 10 })
|
|
57
|
+
: pdfURLOrBuffer;
|
|
58
|
+
|
|
59
|
+
let liteParseWasm: typeof import("@llamaindex/liteparse-wasm");
|
|
60
|
+
try {
|
|
61
|
+
liteParseWasm = await import("@llamaindex/liteparse-wasm");
|
|
62
|
+
await ensureWasmInit(liteParseWasm);
|
|
63
|
+
} catch (e: any) {
|
|
64
|
+
return {
|
|
65
|
+
error:
|
|
66
|
+
"method: 'liteparse-wasm' requires the optional @llamaindex/liteparse-wasm " +
|
|
67
|
+
`dependency: ${e.message}`,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const parser = new liteParseWasm.LiteParse({
|
|
72
|
+
quiet: true,
|
|
73
|
+
ocrEnabled: false,
|
|
74
|
+
ocrFailureFatal: false,
|
|
75
|
+
...liteParseOptions,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
let result;
|
|
79
|
+
try {
|
|
80
|
+
result = await parser.parse(new Uint8Array(buffer));
|
|
81
|
+
} catch (e: any) {
|
|
82
|
+
return { error: e.message };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const html = result.pages.reduce((acc, page) => {
|
|
86
|
+
const body = page.text
|
|
87
|
+
.split(/\n{2,}/)
|
|
88
|
+
.filter((paragraph) => paragraph.trim().length > 0)
|
|
89
|
+
.map((paragraph) => escapeHtml(paragraph).replace(/\n/g, "<br/>"))
|
|
90
|
+
.join("</p><p>");
|
|
91
|
+
return (
|
|
92
|
+
acc +
|
|
93
|
+
`<p id="page-${page.pageNum}">${addPageNumbers ? ` [${page.pageNum}] ` : ""}${body}</p>`
|
|
94
|
+
);
|
|
95
|
+
}, "");
|
|
96
|
+
|
|
97
|
+
let title: string | undefined;
|
|
98
|
+
let author: string | undefined;
|
|
99
|
+
if (addCitation) {
|
|
100
|
+
author = result.creator || result.producer;
|
|
101
|
+
title = result.pages[0]?.text.split("\n").find((line) => line.trim().length > 0);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return { author, title, html, format: "pdf" };
|
|
105
|
+
}
|
package/src/pdf-to-html.ts
CHANGED
|
@@ -29,6 +29,10 @@ import {
|
|
|
29
29
|
convertPDFToHTMLWithLiteParse,
|
|
30
30
|
type LiteParseHTMLOptions,
|
|
31
31
|
} from "./liteparse-to-html";
|
|
32
|
+
import {
|
|
33
|
+
convertPDFToHTMLWithLiteParseWasm,
|
|
34
|
+
type LiteParseWasmHTMLOptions,
|
|
35
|
+
} from "./liteparse-wasm-to-html";
|
|
32
36
|
|
|
33
37
|
/**
|
|
34
38
|
* Which parsing engine {@link convertPDFToHTML} runs.
|
|
@@ -38,8 +42,12 @@ import {
|
|
|
38
42
|
* - `"liteparse"` — delegates to [LiteParse](https://github.com/run-llama/liteparse),
|
|
39
43
|
* a native/OCR-capable parser. Node.js only (ships a napi addon), and requires
|
|
40
44
|
* the optional `@llamaindex/liteparse` dependency to be installed.
|
|
45
|
+
* - `"liteparse-wasm"` — delegates to LiteParse's WebAssembly build. Runs
|
|
46
|
+
* anywhere WASM does — browsers, Cloudflare Workers, and Node.js — and
|
|
47
|
+
* requires the optional `@llamaindex/liteparse-wasm` dependency to be
|
|
48
|
+
* installed. OCR requires passing an `ocrEngine` callback (e.g. tesseract-js).
|
|
41
49
|
*/
|
|
42
|
-
export type ParseMethod = "ts-block-algorithm" | "liteparse";
|
|
50
|
+
export type ParseMethod = "ts-block-algorithm" | "liteparse" | "liteparse-wasm";
|
|
43
51
|
|
|
44
52
|
/**
|
|
45
53
|
* Extracts formatted text from PDF with parsing of linebreaks ,
|
|
@@ -76,6 +84,14 @@ export async function convertPDFToHTML(
|
|
|
76
84
|
return convertPDFToHTMLWithLiteParse(pdfURLOrBuffer, liteParseOptions);
|
|
77
85
|
}
|
|
78
86
|
|
|
87
|
+
if (options.method === "liteparse-wasm") {
|
|
88
|
+
const { method: _method, ...liteParseOptions } = options;
|
|
89
|
+
return convertPDFToHTMLWithLiteParseWasm(
|
|
90
|
+
pdfURLOrBuffer,
|
|
91
|
+
liteParseOptions as unknown as LiteParseWasmHTMLOptions,
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
79
95
|
// try {
|
|
80
96
|
var { addPageNumbers = false, addCitation = true } = options;
|
|
81
97
|
|
|
@@ -223,6 +239,8 @@ export async function convertPDFToHTML(
|
|
|
223
239
|
|
|
224
240
|
export { convertPDFToHTMLWithLiteParse };
|
|
225
241
|
export type { LiteParseHTMLOptions } from "./liteparse-to-html";
|
|
242
|
+
export { convertPDFToHTMLWithLiteParseWasm };
|
|
243
|
+
export type { LiteParseWasmHTMLOptions } from "./liteparse-wasm-to-html";
|
|
226
244
|
export { detectPdfNeedsOcr } from "./detect-needs-ocr";
|
|
227
245
|
export type {
|
|
228
246
|
DetectPdfNeedsOcrOptions,
|
|
@@ -115,6 +115,10 @@ export function isNumberedListItem(string: string): boolean {
|
|
|
115
115
|
return /^[\s]*[\d]*[.][\s].*$/g.test(string)
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
+
export function escapeHtml(text: string): string {
|
|
119
|
+
return text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
|
|
120
|
+
}
|
|
121
|
+
|
|
118
122
|
export function wordMatch(string1: string, string2: string): number {
|
|
119
123
|
const words1 = new Set(string1.toUpperCase().split(' '))
|
|
120
124
|
const words2 = new Set(string2.toUpperCase().split(' '))
|