资讯动态

Xberg 页面级提取实战:用 PageConfig 控制 extract_pages 与页面标记插入

发布时间:2026/10/9 7:36:55 来源:尧图企业网站定制
后端AI 应用NLP【免费下载链接】xbergPolyglot document intelligence with a Rust core: extract text, metadata, images, tables, and structured data from 106 formats across 140 file extensions, plus code intelligence for 371 languages. Fifteen bindings, with CLI, REST API, and MCP server.项目地址https://gitcode.com/gh_mirrors/kr/xberg点击查看免费下载本文以 Xberg 的页面提取与页面标记配置PageConfig为主题围绕 config_pages 契约测试片段 展开通过一个 Ruby 绑定调用演示如何让多页 PDF 的提取结果按页拆分为独立数组ExtractedDocument.pages并在主内容字符串中插入!-- PAGE n --标记。读完本文你将掌握extract_pages、insert_page_markers、marker_format三个配置项的含义、底层实现原理以及它们在 Ruby、Python、TypeScript、Rust、REST API 与 CLI 中的完整用法并能将页面信息与分块、元素级结果、布局检测组合出 RAG 所需的页码感知管线。从一个 Ruby 契约测试片段说起关联文档 是 alef 自动生成并用于跨语言契约验证的测试片段它本身即是一个完整可运行的 Ruby 示例require xberg result Xberg.extract(Xberg::ExtractInput.new(kind: uri, uri: https://example.com/pdf/fake_memo.pdf), { pages { extract_pages true, insert_page_markers true } }) puts result.results[0].mime_type.inspect puts result.results[0].content.inspect这段代码做三件事require xberg加载 Ruby 绑定对应 packages/ruby构造ExtractInput(kind: uri, uri: .../pdf/fake_memo.pdf)以远程 URL 形式传入一个 PDF 文件传入第二个参数即ExtractionConfig的 JSON 形态其中pages配置同时打开extract_pages与insert_page_markers然后打印结果的mime_type与content。对应的契约测试定义在 fixtures/contract/config_pages.json它给出该片段的完整断言results[0].mime_type必须等于application/pdfresults[0].content长度必须 ≥ 10results[0].content必须包含PAGE即页面标记已被插入主内容。测试输入通过 mock server 提供/pdf/fake_memo.pdf返回 200 与application/octet-stream实际文件体来自 crates/xberg/test_documents/pdf/fake_memo.pdf。Rust 侧的 e2e 验证位于 e2e/rust/tests/contract_test.rs 的test_config_pages它用完全相同的{pages:{extract_pages:true,insert_page_markers:true}}配置断言 MIME 与内容形成了Ruby 片段 ↔ Rust 实现 ↔ 契约 fixture的闭环。PageConfig页面提取与跟踪的三开关页面级能力由PageConfig统一配置其定义在 crates/xberg/src/core/config/page.rs字段类型默认值说明extract_pagesboolfalse是否将文档按页拆分为独立数组ExtractedDocument.pagesinsert_page_markersboolfalse是否在主内容字符串中插入页面标记marker_formatString\n\n!-- PAGE {page_num} --\n\n页面标记模板用{page_num}占位符表示页码官方配置参考同样记录在 docs-site/src/content/docs/reference/configuration.md。需要注意PageConfig在ExtractionConfig中是可选的OptionPageConfigNone表示完全禁用页面跟踪marker_format中的{page_num}占位符会被实际页码替换其余字符按字面输出当页面边界可用且配置了分块chunking时chunk 元数据中的first_page/last_page会自动启用无需额外配置见下文与分块的联动。解析与反序列化细节PageConfig标注了#[serde(default, deny_unknown_fields)]含义是三个字段均可省略省略时取各自的默认值extract_pages/insert_page_markers为falsemarker_format为\n\n!-- PAGE {page_num} --\n\n传入未知字段会直接报错这有助于在跨语言绑定中尽早发现拼写错误。因此上面的 Ruby 调用只写了extract_pages与insert_page_markers两个键marker_format自动使用默认模板最终插入的标记形如!-- PAGE 1 --、!-- PAGE 2 --。extract_pagestrue按页拆分的结构化输出结果中的 pages 数组当extract_pages: true时ExtractedDocument会额外携带pages字段——每个元素是一个PageContent。其类型定义在 crates/xberg/src/types/page.rs字段类型说明page_numberu32页码1 起始contentString该页的文本内容tablesVecArcTable该页上检测到的表格image_indicesVecu32该页图片在顶层images集合中的零基索引源码注释明确说明启用页面提取后文档被拆分为按页内容并把表格、图片映射到各自所属的页。tables使用Arc包装以实现零拷贝共享序列化时仍输出普通VecTable保持 JSON 兼容。若同时启用图片提取extract_images trueimage_indices才会被填充它指向顶层ExtractedDocument.images中的下标——也就是说图片数据只存一份页面只持有索引避免大图被逐页复制。页面边界 PageBoundary与按页内容配套的是PageBoundarycrates/xberg/src/types/page.rs它提供从内容字符串字节位置到页码的映射byte_start该页在内容字符串中的起始字节偏移UTF-8 合法边界含byte_end结束偏移不含page_number页码1 起始。这套字节区间设计让下游可以精确回答这段文本属于哪一页也是 chunk 元数据中first_page/last_page的数据来源。各语言绑定的 API 参考均收录了pages字段例如 Ruby API 参考 中ExtractedDocument.pages的描述当页面提取被配置时文档被拆分为按页内容表格与图片映射到各自页面。自动启用规则ElementBased 与 chunking 场景extract_pages并非只能手动开启。在 crates/xberg/src/core/config/extraction/core.rs 中有两条自动启用逻辑当result_format为ElementBased元素级结果兼容 Unstructured 生态时如果pages未显式开启extract_pages配置解析会把它强制置为true当配置了chunking分块时同样会自动开启extract_pages因为分块器需要页面边界来标注每个 chunk 的页范围。这在 docs-site/src/content/docs/migration/from-unstructured.md 的迁移指南中也有体现REST 调用-F config{result_format:element_based,pages:{extract_pages:true}}时二者同时出现。也就是说即使你只关心元素级输出或分块页面信息也会被底层管线自动保留。insert_page_markerstrue在主内容中插入页码标记标记的形态与默认模板insert_page_markers: true会在主content字符串中插入形如!-- PAGE 1 -- !-- PAGE 2 --的标记。默认模板是\n\n!-- PAGE {page_num} --\n\n即标记前后各带一个空行使它在纯文本与 Markdown 渲染中都是独立行。这也正是契约测试断言content 包含PAGE的原因。底层实现两类文档的两种注入路径页面标记的注入发生在核心管线run_pipeline_impl中crates/xberg/src/core/pipeline/mod.rsdoc.page_marker_format config.pages .as_ref() .filter(|p| p.insert_page_markers) .map(|p| p.marker_format.clone()); if let Some(format) doc.page_marker_format.clone() { page_markers::inject_page_marker_elements(mut doc, format); }注意这里用的是Option::filter只有insert_page_markers为true时才把marker_format写入InternalDocument随后调用 crates/xberg/src/core/pipeline/page_markers.rs 的inject_page_marker_elements。该函数区分两种文档形态扁平文档flat提取器把带标记的文本按段切分后标记本身表现为一个匹配marker_line_regex的Paragraph元素。此路径用 marker_line_regex 生成的正则把marker_format中的{page_num}替换为\d逐段匹配命中后把该段落原地转换为RawBlock元素从而让渲染器原样透传标记文本。结构化文档structured内部元素树中页面边界以PageBreak元素表达本身不含标记文本。此时会在文档开头合成一个标记元素并在每个PageBreak之后按下一页页码再合成一个RawBlock标记。若元素自带page编号如第 3 页、第 7 页的元素合成时直接使用元素页号而不是简单递增。边界情况与单元测试page_markers.rs 的测试模块 覆盖了丰富的边界情况可作为理解语义的参考converts_flat_marker_paragraphs_to_raw_blocks扁平路径下标记段落被转换且正文段落保持不变synthesizes_markers_around_page_breaks结构化路径下在页断前后合成标记uses_element_page_numbers_when_present标记使用元素自身的页号如 3、7而非机械递增trailing_page_break_gets_no_dangling_marker文档末尾的页断不会多出一个悬空标记custom_format_with_repeated_placeholdermarker_format中可重复出现{page_num}例如Page {page_num} of document (page {page_num})只要整行匹配即被识别为标记empty_document_is_untouched空文档不注入任何标记non_marker_paragraphs_are_not_converted正文中夹带标记字样但并非独立整行的段落不会被误转换。PageConfig自身的默认值也有单元测试crates/xberg/src/core/config/page.rs锁定三个字段的默认值不被意外改动。自定义 marker_format让标记贴合你的消费端默认的 HTML 注释式标记!-- PAGE n --适合大多数场景但在某些管线中你可能想要别的形态。由于marker_format支持任意字符串其中{page_num}占位符会被页码替换你可以使用纯文本标记\n--- Page {page_num} ---\n便于下游正则直接捕获使用 JSON 友好标记\n[PAGE {page_num}]\n使用带上下文语义的模板如 PAGE {page_num} 。两点提醒marker_format里出现的字面字符会在marker_line_regex中被正则转义crates/xberg/src/core/config/page.rs因此即使模板含[、(等正则元字符也能正确匹配无需手工转义标记的识别以独立整行为前提正则锚定^...$所以正文中若恰好出现相同字样但非整行不会被误判为页标记——这正是上面non_marker_paragraphs_are_not_converted测试保证的行为。在更多语言与入口中使用页面配置契约片段展示的是 Ruby 绑定但同一套pages配置在所有绑定中语义一致JSON 键均为pages。Python 与 TypeScript布局检测指南 中给出了 Python 的典型组合页面提取 布局检测from xberg import ExtractInput, extract, ExtractionConfig, LayoutDetectionConfig, PageConfig output await extract( ExtractInput(kinduri, uridocument.pdf), configExtractionConfig( layoutLayoutDetectionConfig(), pagesPageConfig(extract_pagesTrue), ), ) result output.results[0] for page in result.pages: if page.layout_regions: for region in page.layout_regions: if region.class_name picture and region.confidence 0.9: print(fPage {page.page_number}: diagram detected f(confidence{region.confidence:.2f}, farea{region.area_fraction:.0%}))TypeScript 侧写法为pages: { extractPages: true }camelCase见同一文档的 TypeScript Tab。值得注意的是启用布局检测后再开启页面提取每个PageContent会携带layout_regions含类别、置信度、包围盒、面积占比可用于第几页出现了高置信度插图/表格这类程序化过滤。Rust 绑定Rust 侧直接构造PageConfig结构体同源文档的 Rust Tabuse xberg::{extract, ExtractInput, ExtractionConfig, LayoutDetectionConfig, PageConfig}; let config ExtractionConfig { layout: Some(LayoutDetectionConfig::default()), pages: Some(PageConfig { extract_pages: true, ..Default::default() }), ..Default::default() }; let output extract(ExtractInput::from_uri(document.pdf), config).await?; let result output.results[0]; for page in result.pages { // 逐页访问 page.page_number / page.content }REST API 与 JSON 配置HTTP 接口的配置以 JSON 形式传入键名与 Rust 字段一致。来自 Unstructured 迁移指南 的示例展示了元素级结果与页面提取的组合curl -X POST http://127.0.0.1:8765/extract \ -F filememo.pdf \ -F config{result_format:element_based,pages:{extract_pages:true}}CLIxberg CLI 提供等价的长选项CLI 参考配置键CLI 选项说明extract_pages--extract-pages将页面作为独立数组放入结果insert_page_markers--page-markers在主内容字符串中插入页面标记注释示例xberg extract --extract-pages --page-markers memo.pdf与分块、RAG 的联动页码感知的切片页面配置与分块组合后会得到 RAG 场景中最实用的页码感知能力。在 crates/xberg/src/types/extraction.rs 中每个Chunk携带两个可选字段first_page该 chunk 跨越的首页1 起始last_page末页单页 chunk 时与first_page相等。它们的填充前提正是提取配置中启用了页面跟踪源码注释原文Only populated when page tracking is enabled in extraction configuration。而如前所述只要配置了 chunkingextract_pages会被自动打开因此分块 页码几乎是开箱即用。在 LangChain 集成文档 中官方还给出了按页拆分而非按字符拆分的用法pagesPageConfig(extract_pagesTrue)此时每个Document会获得一个零基的page元数据。这样既可以用PageContent.content直接做每页一个向量也可以依赖first_page/last_page做跨页 chunk 的溯源——例如给 LLM 回答附带见文档第 3–4 页的引用。配置对照速查表目标行为pages配置结果表现按页拆分数组extract_pages: trueresults[0].pages[]按页提供content/tables/图片索引主内容中插入页码标记insert_page_markers: truecontent中出现!-- PAGE n --独立行自定义标记模板marker_format: ...标记按模板渲染{page_num}被替换分块时附带页范围自动配置 chunking每个 chunk 带first_page/last_page元素级结果自动result_format: element_based自动启用页面提取小结从 config_pages 契约片段 出发可以看到 Xberg 的页面能力是一条贯穿配置、管线、结果与测试的完整链路配置上PageConfig的三个字段分别控制按页拆分、插入标记与标记模板实现上页面边界PageBoundary与按页内容PageContent由提取阶段产出标记注入由 core/pipeline/page_markers.rs 在渲染前以RawBlock形式完成并妥善处理扁平/结构化两类文档集成上extract_pages在 ElementBased 与分块场景下自动启用与布局检测、LangChain 等上层生态协同让页码成为 RAG 检索与答案溯源的一等公民。想要亲手验证最直接的方式是运行 e2e/rust/tests/contract_test.rs 的test_config_pages或在任意绑定中以pages: {extract_pages: true, insert_page_markers: true}提取一份多页 PDF观察content中的!-- PAGE n --与pages[]数组——这与你看到的 Ruby 契约测试片段行为完全一致。赞分享后端AI 应用NLP【免费下载链接】xbergPolyglot document intelligence with a Rust core: extract text, metadata, images, tables, and structured data from 106 formats across 140 file extensions, plus code intelligence for 371 languages. Fifteen bindings, with CLI, REST API, and MCP server.项目地址https://gitcode.com/gh_mirrors/kr/xberg点击查看免费下载相关推荐使用 xberg 的 PageConfig 提取分页内容页面数组与页面标记Page Markers实战指南使用 xberg 的 PageConfig 提取分页内容页面数组与页面标记Page Markers实战指南 导读 在从多页 PDF、扫描件或排版复杂的文档后端AI 应用NLPXberg 页面级抽取与页面标记配置实战extract_pages / insert_page_markers 契约解析与实现原理Xberg 页面级抽取与页面标记配置实战extract_pages / insert_page_markers 契约解析与实现原理 本篇技术指南围绕 Xber后端AI 应用NLPXberg 页面追踪与分页标记配置实战基于 Kotlin Android 的 PageConfig 深度指南Xberg 页面追踪与分页标记配置实战基于 Kotlin Android 的 PageConfig 深度指南 Xberg 的 PageConfig 是文档智能后端AI 应用NLP上一篇Translumo打破语言壁垒的终极实时屏幕翻译神器下一篇如何快速掌握屏幕翻译Translumo实时翻译工具完整入门指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑