☰
xberg 批处理提取 API 实战:基于 C FFI 的 extract_batch 字节批量抽取
2026/9/25 2:43:56 网站建设 项目流程
  • 后端
  • AI 应用
  • NLP

【免费下载链接】xberg

Polyglot 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 仓库中的契约测试文档 api_extract_batch_bytes.md 展开,深入讲解 xberg 面向 C 语言暴露的批量提取接口xberg_extract_batch:如何以一段 JSON 字符串一次性提交多个"字节输入"(bytes 输入),由 Rust 核心完成格式识别、内容抽取并批量返回结果。读完本文,你将掌握该 API 的 C 调用范式、输入 JSON 的完整字段语义、底层执行链路以及与之配套的契约测试与断言机制,可以直接在自己的 C/C++ 集成项目中落地"一次调用、多文档抽取"的批处理方案。

一、文档定位:一份可执行的契约测试快照

docs-site/src/snippets-generated/c/contract/api_extract_batch_bytes.md是由 alef 工具自动生成的 C 语言契约测试片段(文件头部注释This file is auto-generated by alef — DO NOT EDIT明确标注了其生成属性),它的作用是:验证 xberg 的extract_batch(批量字节提取)API 在 C 绑定层的行为符合预期。

这份文档本身虽然短小,但它背后挂载了一份完整的机器可读契约 —— api_extract_batch_bytes.json,其中包含:

  • 调用目标:call字段指向extract_batch;
  • 输入构造:input.inputs中以kind: "bytes"提交了一个名为fake_memo.pdf的 PDF 文档(原始字节以十进制数组内联存储);
  • 断言规则:assertions对返回值逐字段校验(详见本文第五节)。

也就是说,本文讲解的不仅是一段 C 示例代码,而是 xberg 批量字节提取能力从"输入建模 → FFI 边界 → Rust 引擎执行 → 结果断言"的完整闭环。

二、API 总览:xberg_extract_batch 的签名与职责

在 C 头文件 xberg.h 中,xberg_extract_batch与单输入接口xberg_extract并列声明:

/** * Extract content from a single bytes or URI input. */ XBERGAlefHandle xberg_extract(XBERGAlefHandle input, XBERGAlefHandle config); /** * Extract content from multiple bytes or URI inputs. */ XBERGAlefHandle xberg_extract_batch(const char *inputs, XBERGAlefHandle config);

其核心语义:

项目说明
函数名xberg_extract_batch
第一个参数inputsconst char *,指向一段JSON 数组字符串,数组元素为输入描述对象(见第三节)
第二个参数configXBERGAlefHandle,一个指向ExtractionConfig的句柄(handle),可通过 xberg 的配置创建 API 获得;传0是非法句柄
返回值XBERGAlefHandle,指向一个ExtractionResult句柄;调用方必须用对应的 free 函数释放(见第四节)
安全约定头文件注释明确要求:所有指针参数必须有效或为 null;返回的指针必须用合适的 free 函数释放

从 API 设计看,xberg_extract_batch把"多个输入"与"一份共享配置"解耦:批内每个输入可以有自己的覆盖配置(per-input extraction overrides,见第三节),同时整批共享一个ExtractionConfig,兼顾了批量吞吐与单文档定制。

三、C 调用示例逐行解析(继承原文档)

原文档给出了完整的、可直接编译的 C 最小示例。下面保留全部代码并逐段解读:

#include <assert.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "xberg.h" int main(void) { XBERGAlefHandle result = xberg_extract_batch("[{\"bytes\":\"pdf/fake_memo.pdf\",\"filename\":\"fake_memo.pdf\",\"kind\":\"bytes\"}]", 0); xberg_extraction_result_free(result); return EXIT_SUCCESS; }

要点解析:

  1. 头文件:xberg.h是 C 绑定的统一入口头文件,声明了xberg_extract_batch、xberg_extraction_result_free等全部 FFI 符号;编译时需确保其所在目录加入头文件搜索路径。
  2. 输入字符串:第一参数是一段 JSON 数组:
    • 元素对象含三个字段:"bytes"(值为"pdf/fake_memo.pdf")、"filename"("fake_memo.pdf")、"kind"("bytes")。
    • 需要说明的是,在真实 FFI 路径上bytes字段承载的是原始文件字节的载体(可以是以字符串形式表达的字节内容或可解析的字节源引用),kind: "bytes"明确告知引擎按内存字节处理而不是按 URI 拉取;filename作为 MIME 探测与元数据提示。
  3. config 传0:这里传入的0是一个"空句柄"。在 FFI 实现中,config == 0会被判为非法句柄并触发错误(见 lib.rs 中ALEF_INVALID_HANDLE_ERROR分支)。在实际工程中,应通过 xberg 的配置句柄 API 创建ExtractionConfig并传入,例如默认配置句柄,而不是字面量0。本示例保留0是为了演示契约测试的边界写法,生产代码请务必替换为有效句柄。
  4. 内存释放:返回的XBERGAlefHandle result必须在用完后调用xberg_extraction_result_free(result)释放,避免句柄注册表与底层对象泄漏——这是 xberg FFI 所有返回句柄的统一资源纪律。

四、输入建模:ExtractInput 的字段语义与 JSON 形态

xberg_extract_batch的输入 JSON 数组元素对应 Rust 侧的ExtractInput结构体,其字段定义如下:

pub struct ExtractInput { pub kind: ExtractInputKind, // bytes | uri(snake_case 序列化) pub bytes: Option<Vec<u8>>, // kind = "bytes" 时的原始字节 pub uri: Option<String>, // 本地路径 / file:// URI / HTTP(S) URL pub mime_type: Option<String>, // MIME 类型提示 pub filename: Option<String>, // 文件名提示,用于 MIME 探测与元数据 pub config: Option<FileExtractionConfig>, // 单输入级提取覆盖配置 }

与之配套的ExtractInputKind枚举只有两个变体:

kind 取值语义必填字段
bytes原始内存字节bytes
uri本地路径、file://URI 或 HTTP(S) URLuri

批量 JSON 的典型形态(对应 extract_batch_uri_basic.json 等批量 fixture 的结构):

[ { "kind": "bytes", "bytes": "...", "filename": "a.pdf", "mime_type": "application/pdf" }, { "kind": "uri", "uri": "/path/to/b.docx" }, { "kind": "uri", "uri": "https://example.com/c.html", "config": { "quality": "high" } } ]

字段设计要点:

  • filename提示:即使只有字节流没有真实文件,filename也能显著提升格式识别准确率;本契约测试中filename: "fake_memo.pdf"正是让引擎把字节按 PDF 处理的依据之一。
  • mime_type提示:可选的 MIME 提示,供格式探测优先级参考。
  • config覆盖:批内单个元素可携带FileExtractionConfig级别的覆盖项,实现"整批共享默认配置 + 个别文档差异化"。

Rust 侧还提供了两个便捷构造器(types.rs):ExtractInput::from_bytes(bytes, mime_type, filename)与ExtractInput::from_uri(uri),非 C 语言绑定(如 Rust 直接调用、其他语言绑定)可以直接使用它们构建输入向量。

五、底层执行链路:从 C 字符串到批量抽取结果

xberg_extract_batch的 FFI 实现位于 lib.rs,其执行链路可概括为四步:

  1. 输入校验与解析:先检查inputs指针非空(空指针返回错误码 1),再通过CStr::from_ptr转为 UTF-8 字符串;随后serde_json::from_str::<Vec<xberg::ExtractInput>>将 JSON 反序列化为输入向量——JSON 格式非法时返回错误码 2 并携带序列化错误信息(L85301-L85319)。
  2. 配置句柄解析:通过locked_handle_ptr::<xberg::ExtractionConfig>从句柄注册表中取出共享配置,同时持有注册表守卫以保证并发安全;config == 0会被判为非法句柄(L85321-L85336)。
  3. 异步执行:在 FFI 运行时上block_on调用 Rust 核心的xberg::extract_batch(inputs_rs, &config_rs),该自由函数委托给进程级默认引擎DEFAULT_ENGINE。
  4. 结果句柄化:成功则通过insert_handle把ExtractionResult登记为句柄返回;失败则设置最后一次错误(set_last_error)并返回0;若 Rust 侧 panic,则用catch_unwind兜底并标记通用 panic 错误(L85338-L85364)。

引擎层(engine/mod.rs)对批量调用还有两个值得注意的语义:

  • 缓存织入:完全由字节组成且整批成功的批次,会按"内容哈希 + 配置"缓存;包含 URI 输入或存在单输入错误的批次不缓存(源码注释明确说明)。
  • 进度事件:每次调用会发出粗粒度的ProgressEvent(开始、完成/失败、缓存命中),ProgressSink与CacheBackend均为可注入接缝,默认是 no-op,不注入时行为与旧实现字节一致。

六、契约断言:如何验证批量字节提取的正确性

契约文档对应的 api_extract_batch_bytes.json 中定义了三条断言,构成对批量字节提取的最低验收标准:

断言类型目标字段期望验证意图
equalsresults[0].mime_typeapplication/pdf字节流被正确识别为 PDF 格式
min_lengthresults[0].content≥ 10抽取出的文本内容非空且有实际长度
contains_anyresults[0].content包含"May 5, 2023"或"Mallori"抽取文本确实还原了文档真实内容

这三条断言从三个维度守护批量 API:格式识别正确性、内容非空、内容真实性(抽取出的不是空壳或乱码)。测试数据fake_memo.pdf是一份标题为fake-memo的单页 PDF(其 PDF 元数据可在 fixture 的字节流中解码看到(fake-memo)与macOS Version 12.5等标记),字节以十进制数组形式内联,保证了契约测试的自包含与可复现。

仓库中还有一批同主题的批量契约 fixture 可供对照阅读,覆盖更多边界场景:

  • extract_batch_bytes_invalid_mime.json:非法 MIME 的字节输入
  • extract_batch_bytes_unsupported_mime.json:不支持的 MIME 类型
  • extract_batch_bytes_size_cap.json:字节大小上限
  • extract_batch_uri_basic.json 与 extract_batch_uri_partial_failure.json:URI 输入与部分失败场景
  • empty_inputs.json:空输入数组

这些 fixture 表明批量 API 的契约面覆盖了输入校验、格式判定、容量限制与部分失败等真实生产场景。

七、工程落地建议

综合契约文档、FFI 实现与批量 fixtures,在 C/C++ 项目中使用xberg_extract_batch时建议遵循以下实践:

  1. 始终传递有效配置句柄:不要照抄契约示例中的字面量0,应通过配置句柄 API 构建默认或定制ExtractionConfig,否则会触发ALEF_INVALID_HANDLE_ERROR。
  2. 构造输入时补全提示字段:kind: "bytes"的输入尽量带上filename(必要时加mime_type),让格式探测更精准;这直接关系到results[i].mime_type与内容抽取质量。
  3. 遵守句柄生命周期:返回的XBERGAlefHandle一律用xberg_extraction_result_free释放;错误时返回0,可通过 xberg 的错误查询 API 读取最后一次错误码与信息。
  4. 理解异步与缓存语义:批量调用在 FFI 层是阻塞式等待异步任务完成;纯字节成功批次默认可走内容缓存,若希望每次强制重抽,可关闭或定制CacheBackend。
  5. 利用契约 fixture 做回归:以 api_extract_batch_bytes.json 为模板,把"输入构造 + 字段断言"的写法引入自己的测试,可低成本守护批量提取行为不回归。

八、延伸阅读

  • C 绑定头文件与全部 FFI 声明:crates/xberg-ffi/include/xberg.h,批量与单输入抽取的文档注释见 L29782-L29794
  • FFI 批量实现源码:crates/xberg-ffi/src/lib.rs#L85270-L85365
  • 统一公开抽取 API(自由函数extract/extract_batch):crates/xberg/src/core/extract/mod.rs
  • 引擎级批量执行与缓存/进度接缝:crates/xberg/src/engine/mod.rs#L90-L101
  • 输入建模与字段定义:crates/xberg/src/core/config/extraction/types.rs#L189-L258
  • 批量契约 fixtures 全集:fixtures/batch
  • 后端
  • AI 应用
  • NLP

【免费下载链接】xberg

Polyglot 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
点击查看免费下载
上一篇:http-parser终极实战指南:5个高级应用场景深度解析
下一篇:Cangjie-SIG/RGF_CJ代码规范:团队协作的编码标准

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询