Files
MinerU/docs/next/api/tasks.md
T

14 KiB
Raw Blame History

V1 tasks:逐文件上传、URL 输入与结果下载链接

状态: Implemented(自部署 API server 与 Router) 读者: HTTP 客户端、SaaS 接口与自部署服务开发者

共同流程是:提交文件清单 → 上传缺失的客户端文件 → 轮询任务 → 使用返回链接下载 ZIP。 清单也支持 URL 输入,由执行服务在后台下载,无需客户端提前获取文件大小或上传字节。 SaaS 可以把上传、下载地址指向 OSS,本地服务可以指向自身的文件接口。客户端只使用服务返回的链接,不拼接存储路径,也不要求 SaaS 实现本地 Files API。 SaaS 的 Go 服务、OSS 配置及部署由其开发方实现;这里定义客户端共同契约。

路由与状态

方法与路径 行为
POST /v1/tasks 表单提交文件清单,或本地单文件 multipart 直传;返回 202。
返回的 upload_method 与 upload_url 每个链接上传一个文件,本地使用 PUT /v1/tasks/{task_id}/uploads/{client_file_id}。
GET /v1/tasks/{task_id} 返回 200 和任务元数据、缺失文件上传项、可用的结果链接。
DELETE /v1/tasks/{task_id} 取消等待上传或正在执行的任务。

任务首次创建就获得稳定的 task_id;执行提交后,它也是当前部署的公开 job_id。等待上传阶段使用 tasks 查询,既有 /v1/parse/jobs 执行资源尚未创建。

状态为 waiting_upload、queued、running、completed、partial、failed、canceled。 全部客户端上传项校验通过后自动启动,不要求客户端发送完成确认。等待上传不占解析并发,也不预占 Router worker。 纯 URL 任务直接进入 queued;URL 下载在后台执行阶段进行,沿用 Job 并发控制。 completed/partial 只在最终 ZIP 已保存后发布;打包时仍为 running。partial 保留成功文件产物及失败文件的错误。

表单请求

POST /v1/tasks 只接受 application/x-www-form-urlencoded 或 multipart/form-data。 所有业务参数放在表单主体;URL 查询参数返回 400 invalid_request,JSON 和原始字节创建请求返回 415。 文件 PUT 使用原始字节。服务返回的 OSS 签名 URL 可以包含查询串,客户端必须原样使用。

表单字段 默认值 说明
manifest 无 JSON 数组形式的文本字段;批量任务必填,最多 100 项。
tier 服务默认值 flash/basic/standard/advanced,受部署能力约束。
ocr_mode auto auto/txt/ocr。
page_range 整本 全局 PDF 页范围;仍支持 1-5、r1、all 等现有语法。
output_formats markdown 可重复字段,支持 markdown/middle_json/structured_content/zip;最终 ZIP 始终生成。
files 无 仅本地单文件 multipart 直传使用,最多一个文件。

每个清单条目包含:

字段 必填 说明
client_file_id 是 一次任务内唯一,1–64 个字母、数字、下划线或短横线。
filename 是 逻辑文件名,保留扩展名;不同条目允许同名。
url 否 文件下载地址,支持 HTTP(S),具体协议受部署策略约束;省略或 null 表示客户端上传。
bytes 条件 上传项必填;URL 项可省略或为 null。提供时必须为严格正整数,用于核对实际字节数。
sha256sum 否 64 位小写十六进制 SHA-256;上传项用于缓存预检与完整性校验,URL 项仅用于下载完整性校验。
page_range 否 逐文件页范围,未提供时继承全局值;非 PDF 仍只支持整本解析。

用真实文件生成清单,再发送表单:

python3 - a.pdf b.pdf > manifest.json <<'PY'
import hashlib
import json
from pathlib import Path
import sys

manifest = []
for index, value in enumerate(sys.argv[1:], start=1):
    path = Path(value)
    hasher = hashlib.sha256()
    with path.open('rb') as source:
        for chunk in iter(lambda: source.read(1024 * 1024), b''):
            hasher.update(chunk)
    manifest.append({
        'client_file_id': f'f{index}',
        'filename': path.name,
        'bytes': path.stat().st_size,
        'sha256sum': hasher.hexdigest(),
    })
print(json.dumps(manifest, ensure_ascii=False))
PY

curl --fail-with-body "$MINERU_API_URL/v1/tasks" \
  -H "Authorization: Bearer $MINERU_API_KEY" \
  --data-urlencode 'tier=flash' \
  --data-urlencode 'ocr_mode=txt' \
  --data-urlencode 'manifest@manifest.json'

匿名本地服务可省略 Authorization。无需 hash 时从清单中省略 sha256sum。 client_file_id 用于关联文件和上传项,不能按文件名判断对应关系。

URL 提交与混合输入

curl --fail-with-body "$MINERU_API_URL/v1/tasks" \
  -H "Authorization: Bearer $MINERU_API_KEY" \
  --data-urlencode 'tier=flash' \
  --data-urlencode 'ocr_mode=txt' \
  --data-urlencode 'manifest=[{"client_file_id":"f1","filename":"document.pdf","url":"https://example.com/download?signature=example"}]'

filename 仍然必填,用于文件类型识别、展示和产物命名,不要求 URL 路径有扩展名。 URL 项的 upload_status 为 not_required,不产生上传链接,也不接受 PUT;源 file_id 为 null。 未声明的 bytes 在下载前为 null,完整下载并校验通过后返回实际大小及 SHA-256。 声明的大小或 hash 不匹配时,该文件失败,不进入解析;空文件同样失败。

同一 manifest 可以混合 URL 与上传项,uploads 仅包含需要客户端上传的条目。 混合任务在这些上传完成后进入执行阶段,URL 下载不需要客户端参与。URL 与 multipart 字节不能同时指定给同一项。 URL 每次重新下载,即使声明的 hash 已在源文件缓存中,也不跳过下载;不要求 HEAD 或 Content-Length。

下载失败、超时或完整性校验失败按文件记录错误,其他文件继续执行;有成功项则返回 partial 和 ZIP,全部失败则为 failed 且无 result_url。 URL 大小不一致使用 bytes_mismatch,hash 不一致使用 file_hash_mismatch。请求格式和部署策略错误仍按接单校验处理。

缓存、上传与恢复

以下缓存规则适用于无 url 的客户端上传项:

  • 全部 hash 命中:返回空 uploads,直接提交解析。
  • 部分命中:仅返回未命中文件的上传项,命中文件已经是 ready。
  • 无 hash 或未命中:上传完整文件;服务端计算实际 hash、校验大小与可选 hash,并去重保存。

缓存是源文件缓存,本次解析仍使用本次 tier、页范围和其他参数。 新请求不会凭文件 hash 复用不匹配的解析结果。

响应中的共同字段:

字段 说明
task_id、status、status_url 稳定任务 ID、当前状态和查询地址。
files 按输入顺序返回清单、upload_status: pending/ready/not_required、逐文件解析状态及错误;URL 项始终为 not_required。
uploads 尚需上传的文件,每项包含 client_file_id、upload_url、upload_method: PUT、upload_headers、expires_at。
result_url 结果未就绪时为 null;completed/partial 时为最终 ZIP 下载地址。
error 任务级错误,例如上传过期或结果打包失败。

本地上传准备默认有效期为 3600 秒,链接的 expires_at 为 Unix 秒。 一个文件完整校验后才变为 ready;中断内容不会进入解析或缓存。 已成功的文件独立保留,后续文件中断只需重传失败文件,继续使用原 task_id。 重复 PUT 已确认文件不会覆盖源字节;同时完成多个文件只会触发一次解析。

本轮提供文件级重试,单个文件失败后从头重传,不支持分块断点续传。 上传响应丢失时先查询任务:文件已 ready 就跳过,否则重试该项。 链接过期而任务仍有效时,重新查询同一任务获取当前链接;本地准备任务整体过期后返回 failed/upload_expired。

本地单文件快捷直传

curl --fail-with-body "$MINERU_API_URL/v1/tasks" \
  -H "Authorization: Bearer $MINERU_API_KEY" \
  -F 'tier=flash' \
  -F 'ocr_mode=txt' \
  -F 'files=@document.pdf'

返回异步任务,不保持连接等待解析。需要声明 hash 时,同时提交仅含一个条目的 manifest 文本字段,例如 -F 'manifest=<single-manifest.json'。

多个文件字段,或者多文件清单混入文件字节,返回 400,应改用逐文件上传链接。 直传时实际发送的字节全部接受完整性校验;它不承诺在 hash 命中时跳过网络传输。稳定的省流量由清单预检提供。

下载结果

轮询只访问响应的 status_url。状态接口不内联 Markdown、Middle JSON 或 ZIP 内容。

  • SaaS 返回 OSS 签名下载地址,客户端直接从 OSS 下载,结果字节不经过 API 网关。
  • 本地返回 /v1/files/{file_id}/content 的完整地址,服务端从已保存文件流式输出。
  • Router 返回自身的 Files 地址并流式代理 worker 产物,不泄露内部 worker 地址。

所有 tasks 自动生成 ZIP;单文件保留现有自包含产物,批量使用 0001/、0002/ 等目录并包含 manifest.json。 manifest 使用 client_file_id 关联输入,directory 指向包内目录,不写入 worker 的私有 task/file ID 或短期下载链接,也不写入源 url 字段。已校验的 URL 输入记录实际大小与 hash。任务 ID 以 HTTP 响应为准。 ZIP 在后台只生成一次;重复查询或下载不重新打包。打包失败返回 failed/result_packaging_failed,不会发布虚假的下载链接。 签名链接过期但产物仍在保留期内时,重新查询任务获得有效地址,不重新提交解析。

认证只附加到与 API 同源的请求。同源由协议、主机、有效端口共同决定;OSS、外部下载地址及跨源重定向不附加 MinerU API Key。 上传额外请求头使用 upload_headers,不硬编码云存储 SDK 或 OSS 域名。

完整客户端示例

scripts/http_task_example.sh 调用同目录的 http_task_example.py,只需要 Python 3.10+ 标准库,无需安装 MinerU 或云存储 SDK。 该脚本接受本地文件路径;URL 提交使用上面的 curl 示例。 默认顺序上传,每个文件最多尝试三次,仅重试网络及临时服务错误;创建请求不自动重试。 脚本校验任务身份、状态和文件对应关系,轮询有预算,下载先写临时文件并验证 ZIP 后再保存最终文件。

MINERU_API_URL=http://127.0.0.1:8000 \
  bash scripts/http_task_example.sh a.pdf b.pdf

SEND_HASH=0 MINERU_API_URL=http://127.0.0.1:8000 \
  bash scripts/http_task_example.sh a.pdf b.pdf

# 恢复时使用首次提交的文件列表和顺序,不重新创建任务。
TASK_ID=job_... MINERU_API_URL=http://127.0.0.1:8000 \
  bash scripts/http_task_example.sh a.pdf b.pdf

UPLOAD_MODE=direct MINERU_API_URL=http://127.0.0.1:8000 \
  bash scripts/http_task_example.sh a.pdf
配置 默认值 说明
MINERU_API_URL 必填 API 或 Router 基地址。
MINERU_API_KEY 空 API 认证,匿名本地服务可省略。
UPLOAD_MODE preflight preflight/direct,direct 只支持一个文件。
SEND_HASH 1 0 时不计算或提交 hash。
TASK_ID 空 继续已有任务,按原文件列表跳过 ready 文件。
MINERU_TIER、OCR_MODE、PAGE_RANGE 服务默认 / auto / 整本 解析参数。
OUTPUT_FORMATS markdown 逗号分隔,自动加入 ZIP。
RESULT_FILE result.zip 最终文件位置。
MAX_POLLS、POLL_INTERVAL 300、1 最多查询次数与间隔秒数。
CONNECT_TIMEOUT、REQUEST_TIMEOUT 10、600 连接和单次传输超时秒数。
MINERU_PYTHON python3 可指定 Python 可执行文件。

退出码为 0(全部成功且保存 ZIP)、2(部分成功且保存 ZIP)、1(失败或取消)、124(轮询预算耗尽)。 取得任务 ID 后发生错误会打印恢复方式;轮询超时不会取消任务。

本地限制与 Router 调度

本地不设固定客户端上传字节数或 PDF 页数上限;usage.limits.max_file_size_bytes 与 max_pages_per_file 为 null。 每任务最多 100 文件。URL 下载沿用 Jobs 的配置:默认只允许 HTTPS,HTTP 需启用 --allow-http-source,超时由 --url-timeout 控制(默认 60 秒),大小由 --max-url-bytes 控制(默认 200 MiB)。这些预算不要求客户端提前声明 bytes。 既有 Jobs 的 inline 来源预算仍按其专用配置生效。 源文件、上传索引和任务记录仍是进程内状态,重启不保证恢复;完成后的任务及产物沿用部署的保留策略。

Router 的 tasks 与 V1 Uploads 复用按调用方隔离的源字节缓存。 全部客户端上传项齐备后才选择并预占 worker,再向该 worker 提交 tasks 和传输其缺失文件。 URL 原样交给支持该来源的 worker 下载,Router 不下载源 URL;URL 下载策略由 worker 配置决定。 worker 负责最终 ZIP,Router 只查询任务与 File 元数据并映射公开下载地址。 同负载轮询,缓存命中不把任务固定到繁忙 worker;一个批量任务仍交给同一个 worker。 失败、取消、终态和后台回收通过同一机制释放预占,等待上传不计入执行负载。

迁移

旧 /v1/file_parse 和 /v1/tasks/{task_id}/result 已移除;不提供同步等待 HTTP 路由或结果正文路由。 客户端改为轮询 status_url 并下载 result_url,删除旧 MODE=sync、RESPONSE_FORMAT、wait_timeout 配置。 旧 tasks JSON 来源、原始字节创建请求和 POST 查询参数不再接受;URL 可通过 tasks 表单 manifest 提交。inline、local、file_id 等资源来源继续使用既有 /v1/parse/jobs 协议。 独立 /v1/uploads 与 /v1/parse/jobs 的 JSON 请求协议保持不变。