🤖座席技能 - - - - - - npx skills@latest add https://github.com/OpenSourceAGI/qwksearch-research-agent --skill extract-pdf (它涵盖了什么)
extract-pdf
当用户上传PDF时,他们希望得到即时聊天响应,而不是在OCR模型上等待5分钟。
即时无后端需要javascript转换PDF (URL或 ArrayBuffer)变成干净的HTML与结构标签-标题,列表,脚注,代码块,粗体/斜体,和目录条目。可以在Node.js、Cloudflare Workers和浏览器环境中工作 pdfjs-serverless。
默认为Slim: 该软件包不捆绑PDF引擎。PDF.js是在运行时从jsdeliver的ESM构建中惰性加载的 pdfjs-serverless (https://cdn.jsdelivr.net/npm/pdfjs-serverless@1/+esm(固定在主版本上)-零依赖,单个~1.6 MB的Mozilla PDF.js的再分发,为无服务器/边缘运行时构建。Node.js和Bun不能导入远程url,所以加载器会返回到本地安装的 pdfjs-serverless 可选依赖。所有与ocr相关的东西(花岗岩) @huggingface/transformers, @napi-rs/canvas)同样是可选的,只在实际使用时才导入。
为了在包含信息图表、图表和表格的页面上实现ocr级保真度,软件包还附带了Granite Docling路径(从前者合并而来) extract-pdf-docling 包):通过前端JS解析器运行所有页面,通过文档OCR运行所有页面 混合动力 模式,只对需要它的页面和ocr进行regex扫描,或者指向远程文档兼容处理器的URL(参见 server/).
安装
bun add extract-pdf
文档和现场演示
site/ 是否有一个Cloudflare Worker为这个包提供文档服务 extract-webpage,另外还有现场演示 /demo:上传PDF或粘贴URL,并获得HTML返回 /api/convert,配合OCR跟进,或通过提取网页 /api/extract. 运行它 bun install 然后在存储库根目录下 cd site && bun run dev. CI在每次涉及它的推送上部署它。看到 网站/ README.md 用于秘密,自定义域,CPU限制和加固。
用法
import { convertPDFToHTML } from "extract-pdf";
const { html, title, author } = await convertPDFToHTML(
"https://example.com/paper.pdf",
);
// or pass an ArrayBuffer from fs.readFile / fetch
const { html } = await convertPDFToHTML(buffer, { addPageNumbers: true });
选项
| 选项 | 默认的 | 描述 |
|---|---|---|
addPageNumbers | false | 插入 [n] 每一页边界处的标记 |
addCitation | true | 读取PDF元数据和要填充的第一页标题 title/author 在返回值中 |
method | "ts-block-algorithm" | 解析引擎—— "ts-block-algorithm", "liteparse",或 "liteparse-wasm" (见下文) |
liteParseOptions | {} | 传递给LiteParse的构造函数 method 是 "liteparse" 或 "liteparse-wasm" |
processor | "frontend" | OCR发生在哪里 "frontend", "hybrid", "docling",或处理器URL(见下文) |
processorUrl | - - - - - - | 使用的远程文档兼容API "hybrid"/"docling" 而不是进程内模型 |
ocrScanOptions | {} | 混合页面扫描的阈值调优(scanPagesForOCR) |
doclingOptions | {} | prompt, maxTokens, scale 为dooping OCR模型 processorHeaders 发送到 processorUrl |
返回值
{ html: string, title?: string, author?: string, format: "pdf",
processor: string, ocrScan: OcrScanResult }
解析方法
convertPDFToHTML 支持三种可互换的解析引擎 options.method:
| 方法 | 引擎 | 环境 | 光学字符识别 |
|---|---|---|---|
"ts-block-algorithm" (默认) | 下面记录的pure-TS管道(这个包) | Node.js, Cloudflare Workers,浏览器 | 否 |
"liteparse" | LiteParse (本地, @llamaindex/liteparse) | node . js只 | 可选 |
"liteparse-wasm" | LiteParse (WASM @llamaindex/liteparse-wasm) | Node.js, Cloudflare Workers,浏览器 | 可选(通过回调) |
import { convertPDFToHTML } from "extract-pdf";
const { html } = await convertPDFToHTML(buffer, { method: "liteparse" });
// Or the WASM build, which also runs in browsers and Cloudflare Workers:
const { html } = await convertPDFToHTML(buffer, { method: "liteparse-wasm" });
LiteParse附带了一个本地(napi)插件,所以 method: "liteparse" 只跑进去
Node.js——它没有被绑定到浏览器或Cloudflare Workers构建中。安装
它明确地(bun add @llamaindex/liteparse),因为它是可选的
依赖;如果没有安装, convertPDFToHTML 返回 { error }
而不是扔。
method: "liteparse-wasm" 将委托给LiteParse的WebAssembly构建,
它可以运行在WASM支持的任何地方——浏览器、Cloudflare Workers和Node.js。
显式安装它(bun add @llamaindex/liteparse-wasm),因为它也是
可选的依赖项;如果没有安装, convertPDFToHTML 返回
{ error } 而不是扔。WASM构建没有内置OCR引擎
通过一项 liteParseOptions.ocrEngine 回调(例如由 tesseract-js)
启用OCR。
默认情况下,两个LiteParse路径在禁用OCR的情况下运行(ocrEnabled: false) - - -
符合这个包的“即时,无后端”的哲学。使用
detectPdfNeedsOcr (见下文)来决定何时值得重新解析文档
liteParseOptions: { ocrEnabled: true }。
处理器模式:前端、混合、文档OCR或远程URL
分开 method, processor 选项决定页面是否删除
通过 花岗岩Docling
OCR模型——保留布局、表格、图表、代码和公式
每页模型推理成本:
processor | 会发生什么 |
|---|---|
"frontend" (默认) | 所有页面都由纯js文本层管道解析。没有OCR,没有模型,即时。 |
"hybrid" | JS管道无处不在+正则表达式扫描(scanPagesForOCR)标记带有信息图表/数字/表格或没有可用文本层的页面;只有那些页面是栅格化的,并使用文档进行OCR识别。 |
"docling" | 每一页都栅格化了,用OCR打印。 |
"https://..." (URL) | 就像 "docling",但是每个页面都被post到与文档兼容的处理器API,而不是在进程中运行模型。 |
// Hybrid: fast JS parse, OCR only the pages that need it
const { html, ocrScan } = await convertPDFToHTML(buffer, { processor: "hybrid" });
console.log(ocrScan.pagesNeedingOcr); // e.g. [3, 7] — pages with tables/figures
// each ocrScan.pages[i] lists reasons: "table-caption", "figure-caption",
// "table-rows", "numeric-grid", "no-text", "sparse-text", "garbled-text"
// All pages through a remote Docling processor (this package's server/):
const { html } = await convertPDFToHTML(buffer, {
processor: "http://localhost:3000",
});
// Hybrid with the OCR offloaded to a remote processor:
const { html } = await convertPDFToHTML(buffer, {
processor: "hybrid",
processorUrl: "http://localhost:3000",
});
使用OCR的页面以 <section class="ocr-page" id="page-N">…</section>
(表格变得真实 <table> 标记、标题 <figcaption>,公式
<code class="formula">,……);OCR失败的页面保留其js解析的HTML。
运行Docling 进程内的 需要可选的 @huggingface/transformers
依赖(ONNX模型) onnx-community/granite-docling-258M-ONNX, ~ 1gb;
第一次使用时下载)和-在Node.js中- @napi-rs/canvas 对页面
光栅化(浏览器/工作器使用) OffscreenCanvas).
正则表达式扫描器也是独立导出的,OCR帮助器也是如此:
import { scanPagesForOCR, doctagsToHtml, ocrImageWithDocling } from "extract-pdf";
const scan = scanPagesForOCR(pageTexts); // string[] of per-page text
// { needsOcr, pagesNeedingOcr: number[], pages: [{ page, reasons, captions }] }
运行文档处理程序服务器
这个 server/ 文件夹包含Hono HTTP API(以前是
extract-pdf-docling 暴露花岗岩Docling模型:
bun run serve:docling # or dev:docling for --watch; port 3000
- 昂首阔步界面:
http://localhost:3000/docs,说明/openapi.json POST /api/v1/convert- - - - - -{ imageUrl, prompt?, maxTokens? }POST /api/v1/convert-base64- - - - - -{ imageBase64, mimeType?, prompt?, maxTokens? }POST /api/v1/convert-stream- SSE令牌流GET /health
一个 server/wrangler.jsonc 将其部署为Cloudflare Worker。
它的任何部署(或具有相同契约的任何API)都可以作为
processor/processorUrl 上面的选项。
在hug Face Spaces上托管处理器
docling-space/ 包装与“拥抱脸”相同的型号
Docker空间:令牌验证,每次生成一个有界队列
模型惰性加载,以及可选的经过处理的HTML输出。它的README有
部署步骤。发送空间的令牌(如果是私人空间,则发送拥抱脸)
读取令牌) doclingOptions.processorHeaders:
const { html } = await convertPDFToHTML(buffer, {
processor: "hybrid",
processorUrl: "https://YOUR_HF_USERNAME-extract-pdf-docling.hf.space",
doclingOptions: {
processorHeaders: {
"X-Docling-Token": process.env.DOCLING_API_TOKEN,
Authorization: `Bearer ${process.env.HF_SPACE_TOKEN}`, // private Space only
},
maxTokens: 1500,
},
});
混合模式在返回之前仍然等待每个标记的页面。回答…
一旦增强,之后就跑 processor: "frontend",返回它的HTML,和
光学字符识别 ocrScan.pagesNeedingOcr 作为后续;这个 现场演示 做
正是如此。
检测PDF是否需要OCR
在提交完整的(可能很慢的)OCR解析之前, detectPdfNeedsOcr
运行一个廉价的、仅限文本层的通道,并报告每个页面是否需要OCR或
其他繁重的解析——用于将文档路由到不同的管道
(快速路径vs. OCR vs.截图vs. LlamaParse或
Docling):
import { detectPdfNeedsOcr, convertPDFToHTML } from "extract-pdf";
const assessment = await detectPdfNeedsOcr(buffer);
// { needsOcr: boolean, pages: PageComplexityStats[], reasons: string[] }
if (!assessment.needsOcr) {
const { html } = await convertPDFToHTML(buffer, { method: "liteparse" });
} else {
console.log("Needs OCR:", assessment.reasons); // e.g. ["scanned", "sparse-text"]
// Route to an OCR-enabled pipeline, e.g.:
const { html } = await convertPDFToHTML(buffer, {
method: "liteparse",
liteParseOptions: { ocrEnabled: true },
});
}
reasons 收集在页面上发现的每个不同的信号; "scanned",
"no-text", "sparse-text", "embedded-images", "garbled",或
"vector-text"。就像 method: "liteparse",这是Node.js只需要
@llamaindex/liteparse。
管道
对象上运行一个顺序的转换链 ParseResult (页→项):
Raw pdfjs text spans
→ CalculateGlobalStats — font heights, distances, format map
→ CompactLines — merge spans on the same y-line into LineItems
→ RemoveRepetitiveElements — strip recurring page headers/footers
→ VerticalToHorizontal — rotate vertical character runs
→ DetectTOC — identify Table of Contents pages, link headings
→ DetectHeaders — classify items as H1–H6 by font height
→ DetectListItems — detect bullet/numbered list items
→ GatherBlocks — group adjacent same-type lines into blocks
→ DetectCodeQuoteBlocks — mark indented blocks as CODE
→ DetectListLevels — add indentation for nested list levels
→ ToTextBlocks — flatten blocks to { category, text } pairs
→ ToHTML — render pairs as <p>, <h1>–<h6>, <ul>, <code>
文件夹结构
src/
pdf-to-html.ts — main entry point (convertPDFToHTML)
liteparse-to-html.ts — "liteparse" method (native napi addon)
liteparse-wasm-to-html.ts — "liteparse-wasm" method (WASM, browser/edge)
ocr-page-scan.ts — regex scan flagging infographic/table pages for OCR
docling-ocr.ts — Granite Docling OCR (local ONNX or remote URL),
│ page rasterization, doctags → HTML
detect-needs-ocr.ts — LiteParse-based OCR routing (Node.js only)
models/ — data classes: Page, ParseResult, TextItem,
│ LineItem, LineItemBlock, Word, BlockType, …
transforms/
│ base/ — abstract Transformation, ToLineItem*, ToLineItemBlock*
│ line-item/ — per-line-item transformations
│ block/ — per-block transformations
│ calculate-global-stats.ts
│ to-text-blocks.ts
│ to-html.ts
utils/
load-pdfjs.ts — lazy CDN loader for pdfjs-serverless
string-functions.ts
page-item-functions.ts
page-number-functions.ts
server/ — Granite Docling HTTP processor (Hono):
server.js, routes.js, schemas.js, model.js, wrangler.jsonc
