首页
/ Umi-OCR 文档识别 HTTP 接口实战:上传 PDF、轮询任务与生成双层可搜索 PDF

Umi-OCR 文档识别 HTTP 接口实战:上传 PDF、轮询任务与生成双层可搜索 PDF

2026-09-05 20:25:52作者:邬祺芯Juliet

Umi-OCR 除了图形界面外,还内置了一套 HTTP 接口,其中“文档识别(PDF 识别)”接口支持上传 PDF/文档、轮询任务状态并导出双层可搜索 PDF 等多种格式。本文以 Umi-OCR 官方接口文档 api_doc.md 为主体,完整覆盖“参数查询 → 上传 → 轮询 → 下载 → 清理”五步调用流程的全部请求/响应格式与参数含义,并结合服务器端源码 doc_server.py 说明任务生命周期、临时目录与自动清理机制,读完即可编写可复制运行的自动化调用脚本。

Umi-OCR 全局设置页

1. 接口总览与前置条件

文档识别是一个异步任务型接口:上传文件后任务在服务端后台运行,客户端通过任务 ID 轮询进度,任务成功结束前无法生成结果文件。完整流程为:

  • 准备工作:调用参数查询接口,确认当前 OCR 引擎支持的参数定义与默认值;
  • 第 1 步:上传待识别文件,获取任务 ID(/api/doc/upload);
  • 第 2 步:通过任务 ID 轮询任务状态,直到 OCR 任务结束(/api/doc/result);
  • 第 3 步:生成目标文件(如双层可搜索 PDF),获取下载链接(/api/doc/download);
  • 第 4 步:通过下载链接 GET 下载结果文件;
  • 第 5 步:清理任务,释放服务器资源(/api/doc/clear/<id>)。

官方提供了两套可直接运行的示例代码:

1.1 前置条件与注意事项

事项 说明
版本要求 v2.1.4 及以上的版本才具有文档识别功能
服务开关 必须允许 HTTP 服务才能使用接口(默认开启),可在 Umi-OCR 全局设置页中找到相关选项;如需局域网访问,将主机切换到任何可用地址
默认端口 1224,可在 Umi-OCR 全局设置中更改
并发限制 由于后端组件的性能限制,对并发支持较差,尽量不要并发调用
偶发报错 长时间、大批量、连续调用时,有小几率出现 Error: connect ECONNREFUSED 之类的 HTTP 报错,重新发起请求即可,只要后台工作线程没有崩溃,此类小问题不会持续影响调用
关闭软件 关闭 Umi-OCR 时若仍有客户端未断开连接,可能导致进程关闭不完全,需等待连接断开或强制结束进程

1.2 任务在服务端的实现结构

从源码结构看,每个上传的文档任务在服务端对应一个 _DocUnit 对象(见 doc_server.py#L90-L163),它记录了任务的全部生命周期状态:

  • state:任务状态,取值为 waiting(排队中)、running(进行中)、success(成功)、failure(失败);
  • is_done:任务是否已结束;
  • processed_count / pages_count:已识别页数 / 总页数,即轮询接口返回的进度来源;
  • start_timestamp / end_timestamp:用于计算临时文件保留时长。

所有任务由 _DocUnitManager 统一管理(添加、按 ID 查询、手动清理、超时自动清理),底层识别任务则委托给 MissionDOC 任务队列执行。理解这一结构后,官方文档中每个接口字段的含义都能与源码一一对应。

2. 准备工作:参数查询接口

[!TIP] 在不同的情况下(比如使用不同的 OCR 引擎插件),第 1 步上传文件时可以传入不同的参数。通过参数查询接口可以获取所有参数的定义、默认值、可选值等信息——既可以手动调用确认,也可以利用返回的字典自动化生成前端 UI

URL:/api/doc/get_options,例:http://127.0.0.1:1224/api/doc/get_options

2.1 请求与响应格式

方法:GET。响应为 JSON 字符串,记录文档上传接口的参数定义。以 PaddleOCR 引擎插件为例,格式化后的返回值为:

{
    "ocr.language": {
        "title": "语言/模型库",
        "optionsList": [
            ["models/config_chinese.txt","简体中文"],
            ["models/config_en.txt","English"],
            ["models/config_chinese_cht(v2).txt","繁體中文"],
            ["models/config_japan.txt","日本語"],
            ["models/config_korean.txt","한국어"],
            ["models/config_cyrillic.txt","Русский"]
        ],
        "type": "enum",
        "default": "models/config_chinese.txt"
    },
    "ocr.cls": {
        "title": "纠正文本方向",
        "default": false,
        "toolTip": "启用方向分类,识别倾斜或倒置的文本。可能降低识别速度。",
        "type": "boolean"
    },
    "ocr.limit_side_len": {
        "title": "限制图像边长",
        "optionsList": [
            [960,"960 (默认)"],
            [2880,"2880"],
            [4320,"4320"],
            [999999,"无限制"]
        ],
        "toolTip": "将边长大于该值的图片进行压缩,可以提高识别速度。可能降低识别精度。",
        "type": "enum",
        "default": 960
    },
    "tbpu.parser": {
        "title": "排版解析方案",
        "toolTip": "按什么方式,解析和排序图片中的文字块",
        "default": "multi_para",
        "optionsList": [
            ["multi_para","多栏-按自然段换行"],
            ["multi_line","多栏-总是换行"],
            ["multi_none","多栏-无换行"],
            ["single_para","单栏-按自然段换行"],
            ["single_line","单栏-总是换行"],
            ["single_none","单栏-无换行"],
            ["single_code","单栏-保留缩进"],
            ["none","不做处理"]
        ],
        "type": "enum"
    },
    "tbpu.ignoreArea": {
        "title": "忽略区域",
        "toolTip": "数组,每一项为[[左上角x,y],[右下角x,y]]。",
        "default": [],
        "type": "var"
    },
    "tbpu.ignoreRangeStart": {
        "title": "忽略区域起始",
        "toolTip": "忽略区域生效的页数范围起始。从1开始。",
        "default": 1,
        "type": "number",
        "isInt": true
    },
    "tbpu.ignoreRangeEnd": {
        "title": "忽略区域结束",
        "toolTip": "忽略区域生效的页数范围结束。可以用负数表示倒数第X页。",
        "default": -1,
        "type": "number",
        "isInt": true
    },
    "pageRangeStart": {
        "title": "OCR页数起始",
        "toolTip": "OCR的页数范围起始。从1开始。",
        "default": 1,
        "type": "number",
        "isInt": true
    },
    "pageRangeEnd": {
        "title": "OCR页数结束",
        "toolTip": "OCR的页数范围结束。可以用负数表示倒数第X页。",
        "default": -1,
        "type": "number",
        "isInt": true
    },
    "pageList": {
        "title": "OCR页数列表",
        "toolTip": "数组,可指定单个或多个页数。例:[1,2,5]表示对第1、2、5页进行OCR。如果与页数范围同时填写,则 pageList 优先。",
        "default": [],
        "type": "var"
    },
    "password": {
        "title": "密码",
        "toolTip": "如果文档已加密,则填写文档密码。",
        "default": "",
        "type": "text"
    },
    "doc.extractionMode": {
        "title": "内容提取模式",
        "toolTip": "若一页文档既存在图片又存在文本,如何进行处理。",
        "default": "mixed",
        "optionsList": [
            ["mixed","混合OCR/原文本"],
            ["fullPage","整页强制OCR"],
            ["imageOnly","仅OCR图片"],
            ["textOnly","仅拷贝原有文本"]
        ],
        "type": "enum"
    }
}

每个参数包含以下属性:

  • title:参数名称;
  • toolTip:参数说明;
  • default:默认值;
  • type:参数值的类型:
    • enum:枚举,参数值必须为 optionsList 中某一项的 [0]
    • boolean:布尔,参数值必须为 true/false
    • text:字符串;
    • number:数字,若属性 isInt==true 则必须为整数;
    • var:特殊类型,具体见 toolTip 说明。

所有参数都是可选的,任一参数不填时将被设为默认值。从源码看,get_doc_options() 在 OCR 通用参数(ocr.*tbpu.*)的基础上追加了文档专属的页数范围、页数列表、密码与内容提取模式,上传时缺失的键也会在这里补全为默认值(见 doc_server.py#L99-L103)。

2.2 参数完整解释

默认值 类型 说明
ocr.language "models/config_chinese.txt" 枚举,可选值:"models/config_chinese.txt""models/config_en.txt""models/config_chinese_cht(v2).txt""models/config_japan.txt""models/config_korean.txt""models/config_cyrillic.txt" 语言/模型库:加载 ./UmiOCR-data/plugins/PaddleOCR-json/models 目录中的引擎配置文件,可切换不同语言的配置。注意:此参数仅适用于 PaddleOCR 引擎插件!其他 OCR 引擎请自行调用参数查询接口获取。
ocr.cls false 布尔,可选 true/false 纠正文本方向:填 true 时启用方向分类,识别倾斜或倒置的文本。可能降低识别速度。注意:仅适用于 PaddleOCR!
ocr.limit_side_len 960 枚举,可选值:96028804320999999 限制图像边长:将边长大于该值的图片进行压缩。较低的限制值可以提高识别速度,较高的限制可以提高大图的识别精度。注意:仅适用于 PaddleOCR!
tbpu.parser "multi_para" 枚举,可选值:"multi_para""multi_line""multi_none""single_para""single_line""single_none""single_code""none" 排版解析方案:按什么方式解析和排序图片中的文字块。可选值含义见上方示例中 tbpu.parser 块的 optionsList
tbpu.ignoreArea [] 嵌套整数列表 忽略区域:处于任意一个忽略区域内的 OCR 文本块将被舍弃。每个忽略区域用矩形坐标 [[左上角x,y],[右下角x,y]] 表示,总列表中可存放多个忽略区域,示例:[[[0,0],[100,50]], [[10,100],[110,150]]]
tbpu.ignoreRangeStart 1 整数 忽略区域生效的页数范围起始,从 1 开始。
tbpu.ignoreRangeEnd -1 整数 忽略区域生效的页数范围结束,可以用负数 -X 表示倒数第 X 页。
pageRangeStart 1 整数 OCR 的页数范围起始,从 1 开始。
pageRangeEnd -1 整数 OCR 的页数范围结束,可以用负数 -X 表示倒数第 X 页。
pageList [] 整数列表 页数列表:可指定单个或多个页数。例:[1,2,5] 表示仅对第 1、2、5 页进行 OCR。若与页数范围(pageRangeStartpageRangeEnd)同时填写,则 pageList 优先。
password "" 字符串 若要识别加密的文档,则需填写文档密码。
doc.extractionMode "mixed" 枚举,可选值:mixedfullPageimageOnlytextOnly 内容提取模式:若一页文档既存在图片又存在文本,如何进行处理。含义依次为:混合OCR/原文本整页强制OCR仅OCR图片仅拷贝原有文本

一个典型的参数字典组装示例(注意:部分参数仅适用于 PaddleOCR 插件,其他插件请先调用查询接口获取规则):

{
    "ocr.language": "models/config_chinese.txt",
    "ocr.cls": true,
    "ocr.limit_side_len": 4320,
    "tbpu.parser": "multi_none",
    "tbpu.ignoreArea": [[[0,0],[100,50]], [[10,100],[110,150]], [[200,50],[300,80]]],
    "pageRangeStart": 1,
    "pageRangeEnd": 10,
    "doc.extractionMode": "fullPage"
}

这些设置最终在第 1 步“上传待识别文档”时随文件发送给服务器。从源码看,服务端只提取 ocr.doc.tbpu. 三个前缀的条目组装任务参数(见 doc_server.py#L119-L126),其余键会被忽略;若文档已加密但未提供 password,上传阶段即返回 code 202 错误。

2.3 参数查询示例代码

JavaScript 示例:

const url = "http://127.0.0.1:1224/api/doc/get_options";
fetch(url, {
        method: "GET",
        headers: { "Content-Type": "application/json" },
    })
    .then(response => response.json())
    .then(data => { console.log(data); })
    .catch(error => { console.error(error); });

Python 示例:

import json, requests

response = requests.get("http://127.0.0.1:1224/api/doc/get_options")
res_dict = json.loads(response.text)
print(json.dumps(res_dict, indent=4, ensure_ascii=False))

手动调用方式:确保 Umi-OCR 已在运行,用浏览器直接访问 http://127.0.0.1:1224/api/doc/get_options,即可看到完整参数定义。

3. 第 1 步:上传待识别文档(/api/doc/upload)

上传一个文档文件(及配置参数),启动识别任务,返回任务 ID。

URL:/api/doc/upload,例:http://127.0.0.1:1224/api/doc/upload

3.1 请求格式

方法:POST。参数为表单 formData,具有两个键值:

  • file:必填。要上传的文件;
  • json:可选。设置参数字典(JSON 字符串),详情见 参数查询接口

JavaScript 示例:

const fileInput = document.getElementById('file_path').files[0]; // 文件对象
const missionOptions = { // 配置参数字典
    "doc.extractionMode": "mixed",
};
// 必须要将字典转换为json字符串
const missionOptionsJSON = JSON.stringify(missionOptions)
// 组装表单
const formData = new FormData();
formData.append('file', fileInput);
formData.append('json', missionOptionsJSON);

let response = await fetch("http://127.0.0.1:1224/api/doc/upload", {
    method: 'POST',
    body: formData
});

3.2 响应格式

返回 JSON 字符串,内容为一个字典,键值为:

  • code:(int)任务状态码。100 为上传成功,其余为失败;
  • data:(string)上传成功时为任务 ID;失败时为失败原因。

从源码看,上传接口的校验顺序为(见 doc_server.py#L406-L504):

  1. 未收到文件 → code 101
  2. 文件名含非法字符会被替换为 _,长度截断至 255;
  3. 文件后缀不在允许列表(DocSuf)内 → code 103
  4. 为每个任务生成 uuid4 作为 dir_id,文件保存到 ./temp_doc/<dir_id>/原文件名,并对路径做越权检查(code 104);
  5. json 表单值解析失败 → code 107,并回滚已保存的临时文件;
  6. 任务提交阶段(_DocUnit 构造)若失败(如加密文档缺密码、引擎报错),返回 code 201/202/203/204 并清理临时目录。

另外注意:官方 api_doc_demo.py 中处理了一个 Linux 上的已知坑——code == 101 时若文件名含非 ASCII 字符,可改用纯 ASCII 的临时文件名(如 temp.pdf)重新构造上传请求。

4. 第 2 步:查询任务状态(/api/doc/result)

传入任务 ID,返回任务的当前执行状态(进行中/已完成)和识别文本。

URL:/api/doc/result,例:http://127.0.0.1:1224/api/doc/result

4.1 请求格式

方法:POST。参数为 JSON 字符串,内容为一个字典,键值为:

  • id:必填,字符串。文件上传接口执行成功后返回的任务 ID;
  • is_data:布尔值,非必填。
    • true:返回值中包含识别结果;
    • false(默认):返回值中不包含识别结果,只有简略的任务状态信息;
  • is_unread:布尔值,非必填。
    • true(默认):返回未读过的识别结果条目(增量式读取);
    • false:返回全部识别结果条目;
  • format:字符串,非必填。
    • "dict"(默认):以字典形式返回详细的识别结果;
    • "text":以字符串形式返回识别结果文本。

从源码 get_result() 可以看到 is_unread 的增量语义实现:每次轮询返回该页之后的未读页结果,并清空 unread_list,因此轮询日志中每页文本只会出现一次,非常适合逐页打印进度。

4.2 响应格式

返回 JSON 字符串,内容为一个字典,键值为:

  • code:(int)任务状态码。100 为查询成功,其余为失败;
  • data:(string/list)查询失败时为失败原因;查询成功且 is_data=true 时为识别内容;查询成功且 is_data=false 时为空数组。

以下内容只有 code==100 时才存在:

  • processed_count:(int)已经识别完的页数;
  • pages_count:(int)总页数;
  • is_done:(boolean)true 表示任务已结束(state 可能为 successfailure),false 表示任务仍在进行中;
  • state:(string)任务状态。值的含义:waiting 任务排队中、running 任务进行中、success 任务成功、failure 任务失败;
  • message:(string)只有 state=="failure" 才存在此项,表示任务失败的原因。注意,就算任务失败,仍可能通过 data 获取已完成的部分任务结果

官方 Python 示例中的轮询写法(摘自 api_doc_demo.py):

data_str = json.dumps({
    "id": id,
    "is_data": True,
    "format": "text",
    "is_unread": True,
})
while True:
    time.sleep(1)
    response = requests.post(url, data=data_str, headers=headers)
    response.raise_for_status()
    res_data = json.loads(response.text)
    assert res_data["code"] == 100, "Failed to get task status: {}".format(res_data)
    print("    Progress: {}/{}".format(res_data["processed_count"], res_data["pages_count"]))
    if res_data["data"]:
        print("{}\n========================".format(res_data["data"]))
    if res_data["is_done"]:
        assert res_data["state"] == "success", res_data["message"]
        break

5. 第 3 步:获取结果下载链接(/api/doc/download)

必须在任务成功结束后才能调用,即第 2 步查询得知 is_done==true && state=="success"。传入任务 ID 和目标文件类型,生成目标文件,返回目标文件的下载链接。

URL:/api/doc/download,例:http://127.0.0.1:1224/api/doc/download

5.1 请求格式

方法:POST。参数为 JSON 字符串,内容为一个字典,键值为:

  • id:必填,字符串。任务 ID;
  • file_types:数组,每一项为字符串。只填写一个值时返回单个文件的下载链接;填写多个值时返回单个 zip 压缩包下载链接,其中打包了多个文件。可选值:
    • "pdfLayered"(默认):双层可搜索 PDF;
    • "pdfOneLayer":单层纯文本 PDF;
    • "txt":带页数等信息的 txt 文件;
    • "txtPlain":只含识别文本的 txt 文件;
    • "jsonl":与 result 接口 format="dict" 的格式类似,每行为一个 JSON 对象;
    • "csv":表格,每行为一页的识别文本;
  • ignore_blank:布尔值。是否忽略空页(没有文字的页数):
    • true(默认):如 txt、csv 等文件中会跳过空页;
    • false:不跳过空页,文件中空页的内容记为空字符串。

    注:Umi-OCR v2.1.4 及以前的版本,ignore_blank 参数存在问题(参数名曾拼写为 ingore_blank),请使用最新版本。

5.2 响应格式

返回 JSON 字符串,内容为一个字典,键值为:

  • code:(int)100 为成功生成目标文件,其余为无法生成目标文件;
  • data:(string)成功时为下载链接,失败时为失败原因;
  • name:(string)只有成功时才存在此项,为下载链接对应的文件名。

从源码 get_files() 可以看到:若任务未结束或失败,返回 code 201;每种 file_types 对应 UmiOCR-data/py_src/ocr/output/ 目录下的一个输出器(如 output_pdf_layered.pyoutput_txt.py),生成多个文件时会自动打包为 [OCR]_文件名前缀.zip,并拼接出形如 {base_url}/api/doc/download/{dir_id}/{文件名} 的下载 URL。

6. 第 4 步:通过链接下载结果文件

第 3 步获取的下载链接,可通过 GET 请求下载,或者直接用浏览器打开下载。

两条重要限制:

  • 链接中类似 id 的部分(dir_id不是任务 ID;
  • 不能通过任务 ID 拼接出下载链接,必须使用第 3 步返回的完整 URL。

源码侧对下载路径做了安全检测,path 不在 ./temp_doc 上传根目录内时抛出 HTTPError(103)(见 doc_server.py#L565-L572)。Python 流式下载的完整写法可参考 api_doc_demo.py,其中按 8KB 分块写入并每 10MB 打印一次进度。

7. 第 5 步:任务清理(/api/doc/clear)

在 URL 中拼接任务 ID,清理对应的任务。

URL:/api/doc/clear/<id>,例:http://127.0.0.1:1224/api/doc/clear/cbe2f874-84a9-48b4-a6c0-9157245f7bae

方法:GET。返回 JSON 字符串,内容为一个字典,键值为:

  • code:(int)状态码。100 为清理成功,其余为清理失败(或不存在对应任务);
  • data:(string)原因。

关于清理的行为说明:

  • 任务清理将删除此任务存放在服务器上的所有临时文件(包括上传的文件);如果任务进行中时执行清理,将强制终止任务;
  • 一个任务被清理后,无法再获取任务状态、访问下载链接;
  • 建议调用者在每次完成任务后手动清理任务,以便及时释放服务器资源。如果不手动清理,任务会在 24 小时后自动清理
    • 如果任务上传后一直在进行,那么最长持续运行 24 小时;
    • 如果任务已完成,那么从完成的时候开始算,最长保留 24 小时;
  • 如果 Umi-OCR 被意外关闭,重新启动时会自动清理上次遗留的所有任务。

这与源码中的常量设定一致:TEMP_FILE_RETENTION_DURATION = 24(小时)、TEMP_FILE_CLEANUP_INTERVAL = 0.5(小时),自动清理循环每半小时检查一次超时任务(见 doc_server.py#L21-L23auto_clear());服务初始化时(init())会先删除并重建 ./temp_doc 目录,即“重启自动清理遗留任务”的实现。手动清理时若 OCR 线程仍占用文件导致 PermissionErrorclear() 会重试等待最多 20 秒(见 doc_server.py#L294-L305)。

8. 完整调用流程小结

将五步串起来的最小闭环是:

  1. GET /api/doc/get_options 确认参数;
  2. POST /api/doc/upload(formData:file + json)得到任务 ID;
  3. 循环 POST /api/doc/result(建议 is_data=trueis_unread=trueformat="text"),直至 is_donestate=="success"
  4. POST /api/doc/download 指定 file_types(如 ["pdfLayered"])获取下载链接与文件名,再 GET 该链接保存文件;
  5. GET /api/doc/clear/<任务ID> 释放资源。

完整的 Python 与 Web 版参考实现分别位于 api_doc_demo.pyapi_doc_demo.html,可直接复制后修改 file_pathoptions 使用。同一 HTTP 服务下还另有图片 OCR 接口(api_ocr.md)与二维码接口(api_qrcode.md),其参数查询机制与本文一致,可按同样方式先查 get_options 再发起请求。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
588
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
906
1.83 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
891
5.79 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.53 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.34 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
988
506
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384