通过回调使用自定义 AI 模型
概述
从 SDK v4.1.0 开始,ComPDF Conversion SDK 暴露了基于回调的扩展点,允许您插入自己的 AI 推理引擎来进行 OCR、版面分析和表格识别。您可以不再依赖通过 CPDF_SetDocumentAIModel 加载的内置 DocumentAI 模型,而是使用任何模型或服务运行推理,并将结果以 JSON 字符串返回给 SDK。
当 CConvertCallback 上注册了相关回调对后,SDK 会跳过该能力的内置模型调用,转而使用您的 JSON 输出。如果回调对为 NULL,SDK 会回退到内置的 DocumentAI 模型(如果可用)。
回调对
每种 AI 能力使用两个回调:一个触发器回调(由 SDK 调用,传入临时目录中保存为 PNG 的页面图像路径)和一个结果获取器回调(紧接着由 SDK 调用以检索 JSON 字符串)。
| 能力 | 触发器回调 | 结果获取器回调 | 触发条件 |
|---|---|---|---|
| OCR | ocr | get_ocr_result | enable_ocr = true |
| 版面分析 | layout | get_layout_result | enable_ai_layout = true 或 enable_ocr = true |
| 表格识别 | table | get_table_result | enable_ai_table_recognition = true 且版面分析检测到表格区域 |
规则:
- 触发器接收 PNG 文件的 UTF-8 路径。推理成功返回
true,返回false则 SDK 忽略该页面结果。 - 获取器必须返回 UTF-8 JSON C 字符串。指针必须在 SDK 完成解析之前保持有效,通常直到同一获取器的下一次调用。
- 每种能力的两个回调必须同时设置。若只提供其中一个,SDK 将回退到内置路径。
- JSON 中的坐标必须位于触发器接收到的图像的像素空间中,左上角为原点,X 向右,Y 向下。
示例
#include <stdbool.h>
#include <stddef.h>
#include "compdf_common_c.h"
#include "compdf_conversion_c.h"
static char g_ocr_json[4096];
static char g_layout_json[4096];
static char g_table_json[4096];
static bool MyOcrTrigger(const char* image_path)
{
return RunMyOcrModel(image_path, g_ocr_json, sizeof(g_ocr_json));
}
static const char* MyOcrGetter(void)
{
return g_ocr_json;
}
static bool MyLayoutTrigger(const char* image_path)
{
return RunMyLayoutModel(image_path, g_layout_json, sizeof(g_layout_json));
}
static const char* MyLayoutGetter(void)
{
return g_layout_json;
}
static bool MyTableTrigger(const char* image_path)
{
return RunMyTableModel(image_path, g_table_json, sizeof(g_table_json));
}
static const char* MyTableGetter(void)
{
return g_table_json;
}
int main(void)
{
CPDF_LicenseVerify("LICENSE_KEY", "device_id", "app_id");
CPDF_Initialize(CPDF_TEXT("resource"));
CConvertCallback callback = {0};
callback.ocr = MyOcrTrigger;
callback.get_ocr_result = MyOcrGetter;
callback.layout = MyLayoutTrigger;
callback.get_layout_result = MyLayoutGetter;
callback.table = MyTableTrigger;
callback.get_table_result = MyTableGetter;
COCRLanguage languages[] = {e_CENGLISH};
CConvertOption option = CPDF_DefaultConvertOption();
option.enable_ocr = true;
option.enable_ai_layout = true;
option.languages = languages;
option.language_count = 1;
CPDF_StartPDFToWord(CPDF_TEXT("input.pdf"), CPDF_TEXT(""), CPDF_TEXT("output.docx"), option, &callback);
CPDF_Release();
return 0;
}您可以只注册想要覆盖的能力,其余保留 NULL 以保持内置行为。
线程安全与生命周期
- 回调从 SDK 转换线程调用。如果模型引擎在多处共享,请以线程安全的方式实现。
- 位于
image_path的 PNG 图像存放在 SDK 临时目录中,触发器返回后可能会被很快删除。请在返回之前复制或处理它。 - 获取器返回的 JSON 指针必须在同一获取器再次被调用或转换任务结束之前保持有效。
OCR 结果 JSON 模式
由 get_ocr_result 返回。SDK 会根据 words[](如果提供)或通过均匀分割 span 矩形来填充每个 text_spans[].chars[]。
{
"text_spans": [
{
"text": "Hello World",
"confidence": 0.98,
"rotation": 0.0,
"rect": { "left": 120, "top": 80, "right": 320, "bottom": 110 },
"style": {
"font_size": 18.0,
"font_color": { "r": 0, "g": 0, "b": 0 }
},
"words": [
{ "text": "Hello", "rect": { "left": 120, "top": 80, "right": 200, "bottom": 110 } },
{ "text": "World", "rect": { "left": 210, "top": 80, "right": 320, "bottom": 110 } }
]
}
]
}| 字段 | 类型 | 必需 | 描述 |
|---|---|---|---|
text_spans | array | 是 | 页面上识别的文本跨度。 |
text | string | 是 | 跨度的 UTF-8 文本内容。 |
confidence | number | 否 | 0.0 – 1.0。低于 0.1 的跨度将被丢弃。 |
rotation | number | 否 | 文本旋转角度(度数)。默认 0。 |
rect | object | 是 | 图像像素中的边界框(left/top/right/bottom)。 |
style.font_size | number | 否 | 估计的字体大小(像素)。 |
style.font_color | object | 否 | { r, g, b } 0 – 255。 |
words | array | 否 | 逐词边界框。若省略,SDK 将均匀分割 span 矩形。对于 CJK 与拉丁文混合行,强烈建议提供以正确排列字形间距。 |
版面分析结果 JSON 模式
由 get_layout_result 返回。置信度低于 0.45 的对象将被丢弃。
{
"objects": [
{ "type": "title", "confidence": 0.95, "rect": { "left": 60, "top": 50, "right": 540, "bottom": 90 } },
{ "type": "paragraph", "confidence": 0.97, "rect": { "left": 60, "top": 100, "right": 540, "bottom": 220 } },
{ "type": "figure", "confidence": 0.92, "rect": { "left": 80, "top": 240, "right": 520, "bottom": 460 } },
{ "type": "table", "confidence": 0.93, "rect": { "left": 60, "top": 480, "right": 540, "bottom": 700 } }
]
}支持的 type 值:
| 值 | 含义 |
|---|---|
paragraph | 正文段落 |
title | 标题 |
figure | 图像或图形 |
figure_title | 图形标题头 |
figure_caption | 图形标题文本 |
table | 表格区域。表格是否有边框由表格识别阶段决定,而非由版面标签决定。 |
table_title | 表格标题头 |
table_caption | 表格标题文本 |
ordered_list | 有序列表 |
unordered_list | 无序列表 |
catalogue | 目录 |
formula | 数学公式 |
code | 代码块 |
algorithm | 算法块 |
header | 页眉 |
footer | 页脚 |
page_number | 页码 |
reference | 参考文献或引用 |
未列出的 type 值对应的对象将被忽略。请使用此表中的值作为自定义输出中的规范版面标签。
表格识别结果 JSON 模式
由 get_table_result 返回,每个检测到的表格区域返回一次。多边形使用八个整数 [x0, y0, x1, y1, x2, y2, x3, y3],顺序为左上、右上、右下、左下。
{
"type": "table_with_line",
"position": [60, 480, 540, 480, 540, 700, 60, 700],
"rows": 3,
"cols": 2,
"angle": 0.0,
"height_of_rows": [40, 60, 60],
"width_of_cols": [200, 280],
"table_cells": [
{
"start_row": 0,
"end_row": 0,
"start_col": 0,
"end_col": 0,
"cell_background_color_r": 240,
"cell_background_color_g": 240,
"cell_background_color_b": 240,
"position": [60, 480, 260, 480, 260, 520, 60, 520]
}
]
}| 字段 | 类型 | 描述 |
|---|---|---|
type | string | table_with_line 表示有边框的表格;其他值视为非标准(无边框)表格。 |
position | int[8] | 图像像素中的表格多边形。 |
rows / cols | int | 行数 / 列数。 |
angle | number | 倾斜角度(度数)。 |
height_of_rows | int[] | 每行像素高度(长度 = rows)。 |
width_of_cols | int[] | 每列像素宽度(长度 = cols)。 |
table_cells[] | array | 每个合并单元格一条记录。 |
start_row / end_row | int | 单元格的行跨度(含)。 |
start_col / end_col | int | 单元格的列跨度(含)。 |
cell_background_color_* | int | 单元格背景颜色分量(0 – 255)。 |
position | int[8] | 图像像素中的单元格多边形。 |
提示:验证 JSON
如果需要参考输出进行对比,可以先使用内置 DocumentAI 模型运行一次转换。SDK 内部使用相同的 JSON 结构,因此您的自定义输出应遵循相同的结构。