新年第一天:从 MinerU API 深度 Debug 到完成97页印尼投资指南翻译

开篇:一份测试文档

2026年1月1日,新年第一天。

前几天,一位挚友发来一份文档——《Indonesia Investment Guidebook》,印尼投资部的官方投资指南,97页,全是投资政策、税收优惠、经济特区这些硬核内容。

她是 Master-Translator 这个项目的灵感来源。最近我们在聊能不能把 AI 翻译这件事进一步技术落地,她从一位律所合伙人那里拿到这份文档,想让我测试一下实际效果。

正好。前阵子刚用 Master-Translator 翻译了一本320页的技术书籍,这97页官方文档是个不错的试金石。

结果,MinerU 桌面版给我来了个下马威——进度条走到一半就卡死了。没有报错,没有日志,就是不动了。

这新年第一天,总不能就这么认输吧?

MinerU 不是有远程 API 吗?既然桌面版不行,那就直接调 API。更进一步,能不能逐页诊断,找出到底是哪一页有问题?

窗外朋友圈还在刷跨年祝福,我已经打开了 Claude,准备开干。

Part 1: MinerU API 的"考古"之旅

从官方文档到 GitHub 源码

MinerU 官方提供了 API 服务(mineru.net),但官方文档的 API 版本信息有些混乱。我最初尝试的端点都返回 404:

# 官方文档说的 v1 接口 - 404
POST https://mineru.net/api/v1/pdf/convert

# 我猜测的 v3 接口 - 还是 404  
POST https://mineru.net/api/v3/extract

这让我意识到:官方文档可能已经过时

转机来自 GitHub。在 MinerU 官方仓库中,我找到了一个 MCP Client 示例代码,里面暴露了真正的 API 端点:

# 正确的 v4 API 端点
BASE_URL = "https://mineru.net"
BATCH_URL = f"{BASE_URL}/api/v4/file-urls/batch"
RESULT_URL = f"{BASE_URL}/api/v4/extract-results/batch/{{batch_id}}"

教训一:当官方文档过时时,去看官方的 SDK 或 Client 代码。

OSS 上传的代理陷阱

找到正确端点后,新的问题出现了。API 的工作流程是:

  1. 调用 /api/v4/file-urls/batch 获取 OSS 上传 URL
  2. PUT 文件到 OSS URL
  3. 轮询 /api/v4/extract-results/batch/{batch_id} 获取结果

第一步成功了,但第二步——PUT 上传到阿里云 OSS——失败了:

SSL: CERTIFICATE_VERIFY_FAILED

排查后发现:我的系统配置了代理,而阿里云 OSS 的 SSL 证书验证在代理环境下出了问题。

解决方案出奇的简单:

# 创建一个不使用系统代理的 session
session = requests.Session()
session.trust_env = False  # 关键!绕过系统代理

# 使用这个 session 进行 OSS 上传
session.put(oss_url, data=file_data)

教训二:当 HTTPS 请求莫名其妙失败时,检查代理配置。

Content-Type 的微妙差异

还有一个坑:上传到 OSS 时,不要设置 Content-Type header

# 错误 ❌
headers = {"Content-Type": "application/pdf"}
requests.put(oss_url, data=data, headers=headers)

# 正确 ✅ - OSS 签名 URL 已包含 Content-Type 信息
requests.put(oss_url, data=data)

如果自己设置 Content-Type,会与预签名 URL 中的签名不匹配,导致 403 Forbidden。

Part 2: 逐页诊断 PDF 问题

为什么桌面版失败?

MinerU 桌面版处理这份97页 PDF 时失败,但没有给出具体原因。我的假设是:可能某些页面有特殊格式导致解析失败。

为了验证这个假设,我写了一个逐页诊断脚本:

# diagnose_pdf_official.py 核心逻辑
from pypdf import PdfReader, PdfWriter
import tempfile

def diagnose_pdf(pdf_path, start_page=1, end_page=None):
    """逐页提取并测试每一页"""
    reader = PdfReader(pdf_path)
    total_pages = len(reader.pages)
    
    results = []
    for page_num in range(start_page, min(end_page or total_pages, total_pages) + 1):
        # 创建单页 PDF
        writer = PdfWriter()
        writer.add_page(reader.pages[page_num - 1])
        
        with tempfile.NamedTemporaryFile(suffix='.pdf') as tmp:
            writer.write(tmp.name)
            
            # 调用 API 测试这一页
            result = client.extract_file(tmp.name)
            results.append({
                'page': page_num,
                'success': result.success,
                'error': result.error if not result.success else None
            })
    
    return results

测试结果:全部通过!

运行诊断脚本测试前5页:

python diagnose_pdf_official.py "Indonesia_Investment_Guidebook.pdf" \
    --start 1 --end 5 --model vlm

结果出人意料:

📊 诊断结果汇总:
================
成功: 5/5 页 (100.00%)
失败: 0 页

✅ 所有测试页面均处理成功!

所有页面都能正常解析! 这意味着桌面版的失败可能是其他原因(内存、超时、或版本差异)。

既然 API 可以正常工作,那就直接用 API 处理整个文档吧。

Part 3: 完整解析与翻译

使用 VLM 模型解析

VLM(Vision Language Model)是 MinerU 提供的高级模型,相比传统 OCR 管道,对表格和复杂布局的处理更好。

python mineru_client.py "Indonesia_Investment_Guidebook.pdf" \
    --model vlm \
    --output ./output

约3分钟后,解析完成:

✅ 提取成功!
  批次ID: a5d6e18f-69d6-4428-bd3c-065adeaa2e8d
  ZIP URL: https://cdn.mineru.net/...
  耗时: 188.2 秒
📥 结果已下载到: ./output
  - full.md (168KB)
  - images/ (119张图片)

解析结果统计

指标数值
原 PDF 页数97 页
Markdown 行数2,242 行
总字符数172,160
图片数量119 张
HTML 表格数26 个

表格被完美提取为 HTML 格式,包括复杂的合并单元格:

<table>
  <tr>
    <td rowspan="2">Tax Holiday</td>
    <td colspan="4">Applying general provisions...</td>
    <td>TH is applicable</td>
  </tr>
  ...
</table>

构建术语表

投资类文档最怕的就是术语翻译不一致——同一个机构名,前面叫"投资协调委员会",后面又变成"投资管理局",读者会懵。

所以在翻译之前,我先让 Claude 基于文档内容构建了一个72条术语的专业术语表:

[
  {"term": "FDI", "translation": "外国直接投资", "note": "Foreign Direct Investment"},
  {"term": "BKPM", "translation": "印尼投资协调委员会", "note": "Badan Koordinasi Penanaman Modal"},
  {"term": "OSS RBA", "translation": "在线单一提交系统(风险评估版)", "note": "Online Single Submission Risk Based Approach"},
  {"term": "Job Creation Law", "translation": "创造就业法", "note": "2020年第11号法律"},
  {"term": "SEZ", "translation": "经济特区", "note": "Special Economic Zone"},
  {"term": "Tax Holiday", "translation": "税收假期", "note": "对先驱产业的企业所得税减免"},
  // ... 还有66条
]

这个术语表里有机构名称、法律法规、税收政策术语,还有印尼特有的一些制度名词。有了它,Master-Translator 在翻译时就能保证全文术语一致。

这也是为朋友做事的态度吧——要么不做,要做就认真做。

使用 Master-Translator 翻译

mcp_master-transl_translate_document(
    document_path="/path/to/output/full.md",
    target_language="chinese",
    model="deepseek-official"
)

翻译统计:

指标数值
翻译模式并行 (5 并发)
分块数16 块
失败数0
输入字符172,033
输出字符66,432
耗时248 秒 (~4分钟)
估算成本$0.25

使用 DeepSeek V3 官方 API,4分钟完成17万字符的翻译,成本不到2元人民币。

Part 4: 翻译质量验证

翻译完成后,我对中英文版本进行了详细对比:

结构完整性检查

# 图片引用数量
grep -c '!\[' full.md full_chinese.md
# full.md: 90
# full_chinese.md: 90 ✅

# 表格数量
grep -c '<table>' full.md full_chinese.md
# full.md: 26
# full_chinese.md: 26 ✅

发现并修复的问题

在 Pandoc 转换 Word 时,发现一个警告:

[WARNING] Could not fetch resource images/a935da19...0836c026f68.jpg

排查后发现:翻译过程中,图片路径中的一个字符被错误修改

原文: ...281d083f6c026f68.jpg  (f)
译文: ...281d0836c026f68.jpg   (6) ← 错误!

这是一个罕见的 edge case——长 hash 字符串在 LLM 处理时偶尔会出现字符替换。用 sed 快速修复:

sed -i '' 's/281d0836c026f68/281d083f6c026f68/g' full_chinese.md

翻译质量评估

维度评分说明
完整性⭐⭐⭐⭐⭐所有内容均已翻译,无遗漏章节
准确性⭐⭐⭐⭐⭐专业术语翻译准确一致
格式保留⭐⭐⭐⭐⭐表格、图片、公式完整保留
流畅度⭐⭐⭐⭐☆语句通顺,偶有直译痕迹

示例对比:

原文:

The Job Creation Law, a comprehensive law that governs and amends many provisions in various sectors, was signed by President Joko Widodo on 2 November 2020.

译文:

《创造就业法》是一部综合性法律,旨在进行结构性改革并加速经济转型,于2020年11月2日由佐科·维多多总统签署,该法管辖并修订了多个领域的许多规定。

术语一致性示例:

  • Ministry of Investment/BKPM投资部/印度尼西亚投资协调委员会(BKPM)
  • OSS RBA在线单一提交系统(OSS RBA)
  • Tax Holiday税收假期

Part 5: Word 导出的两跳转换

翻译完成后,需要导出为 Word 文档。这里有个技巧:

直接转换的问题

# 直接 MD → DOCX:表格格式丢失
pandoc full_chinese.md -o full_chinese.docx

Pandoc 直接转换时,HTML 表格(尤其是带 colspan/rowspan 的)会变成纯文本。

两跳转换方案

# 步骤1: Markdown → HTML(嵌入所有资源)
pandoc full_chinese.md -o full_chinese.html \
    --embed-resources --standalone --mathjax

# 步骤2: HTML → Word
pandoc full_chinese.html -o full_chinese.docx

这个方案的原理:

  1. Pandoc 的 HTML 输出器完美保留 HTML 表格
  2. Pandoc 的 HTML→DOCX 转换器能正确解析已渲染的 HTML

最终生成了 9.3MB 的完整 Word 文档:

  • ✅ 119 张图片完整嵌入
  • ✅ 26 个表格正确渲染(包括合并单元格)
  • ✅ 数学公式通过 MathJax 完美呈现

技术复盘

既然博文都写到这里了,不如把整个工具链和踩过的坑也记录一下,方便日后参考。

工具链总结

PDF 文档
    ↓ (MinerU VLM API)
Markdown + Images
    ↓ (术语表构建)
terminology.json
    ↓ (Master-Translator + DeepSeek)
中文 Markdown
    ↓ (Pandoc 两跳转换)
Word 文档

踩坑清单

问题解决方案
API 端点 404查看官方 SDK 源码找到 v4 端点
OSS 上传 SSL 错误设置 trust_env=False 绕过代理
OSS 上传 403 错误不要手动设置 Content-Type
图片路径字符被改用 sed 修复,并对比检查
表格格式丢失使用 MD→HTML→DOCX 两跳转换
LaTeX 公式显示异常清理 OCR 产生的无效公式标记

时间线

时间工作内容
下午 2:00开始研究 MinerU API
下午 3:00调通 API 端点,解决代理问题
下午 4:00完成逐页诊断脚本
下午 5:00全文解析完成,开始构建术语表
下午 6:00翻译完成,开始质量检查
晚上 7:00修复图片路径问题,完成 Word 导出
晚上 8:00项目完成 🎉

彩蛋:OCR 的"幻觉"

最后说个好玩的事。

在质量检查时,我发现 Word 文档中有些地方显示着奇怪的 \( xxx \) 符号。追查发现,MinerU 的 VLM 模型在解析 PDF 封面时产生了"OCR 幻觉":

# 原文档第二部分封面被识别成了这些乱码:
NO SMOKING
PVEHICLEX1
NO6CARDK
(2) $\mathrm{{NaOH}}$ 扩散的体积为   ← 这是什么鬼?
H21HxTg

是的,一份印尼投资指南的封面,被 OCR 成了化学方程式 NaOH

我把这个截图发给挚友,她说可以当成"AI 也会胡说八道"的案例存档。

不过这也提醒我们:即使是最先进的 VLM 模型,在处理设计感强的封面页时,也可能产生完全离谱的输出。好在这些乱码只出现在封面区域,正文内容是没问题的。

结语:新年的正确打开方式

晚上8点,我把最终的 Word 文档和术语表打包发给了挚友,让她转交给律所那边。

发完消息,对方还没回复——大概还在享受新年假期吧。

不过这不重要。重要的是,这次测试让我对 Master-Translator 的实战能力更有信心了:97页官方文档,从 PDF 解析到中文 Word 导出,6小时搞定,成本不到2块钱。当然,这6小时里有一半时间是在调 API、抓 Bug。但正是这些折腾,让整个过程变得有趣。

2026年的第一天,就这样在 API Debug 和翻译校对中度过。没有跨年晚会,没有朋友聚餐,只有屏幕上跳动的代码和一份渐渐成型的中文译稿。

窗外天色已暗,桌上的咖啡早就凉透了。

但心里是热的——因为这个项目,正在从"个人工具"慢慢走向"可能真的有用"。

新年第一天,用来折腾有意义的事情——这大概就是我的仪式感吧。 🚀


本文使用的工具:

如果你对 AI 翻译或 MCP 开发感兴趣,欢迎在评论区交流!

留言与讨论