【文献翻译】关于文献翻译的思考以及简单的工作流程
- 内容介绍
- 文章标签
- 相关推荐
这两天一直在思考怎么将PDF英文文献翻译成好理解、好阅读、好查阅的中文形式,研究了一下将整个流程整理一下。
总体流程
对于一个PDF,直接对译为中文PDF在很多时候是不合适的,主要问题在于中英文表述相同意义下的字数不同,以及对公式处理不佳。考虑这一点,找到一个合适的中间格式来转可能更好。
显然markdown完美符合这个中间格式的要求,换句话说我们第一步就要将PDF转成markdown,然后因为markdown纯文本的格式,直接按段落分丢给LLM翻译就行了
而且markdown本身就有极佳的可读性,也可以借助mdbook等SSG工具转换成网页从而在各个端都能访问阅读
用流程图描述就是这样
graph LR
Start[原始 PDF 文件] --> CoreProcess
subgraph CoreProcess [核心处理流程]
direction LR
Step1[PDF 转换为 Markdown]
Step2[按段落分割纯文本,调用 LLM 进行翻译]
Result[中文 Markdown 文件]
Step1 --> Step2 --> Result
end
CoreProcess --> Final[生成网页, 实现多端访问]
PDF 2 MD
那么第一问题来了,怎么将PDF转换为md
考虑到公式、表格、图片三个要素的存在,转换方式一定是要完美保持这三个东西的,这个可以借助一些专门的OCR模型来做
我试了好几个,最后选择的是MonkeyOCR,相较于Deepseek OCR、PaddleVL OCR等几个模型,这个主要的好处是不费劲,速度和效果和Deepseek OCR差不多,比PaddleVL OCR好配置。
但是本地用这些OCR模型对显存的要求还是蛮高的,尽管模型本身只有3B参数,但是实际上跑下来大概需要12-16G显存才能运行,我使用一块V100才勉强压下来
但是也有其他方式来进行PDF转换,不少OCR提供商都有DEMO or 官方网站来进行转换,比如:dots.ocr,MinerU.
我用dots.ocr为例,上传文献之后就可以直接得到OCR后的结果,下载即可
dots.ocr DEMO1904×1710 523 KB
下载后解压完得到如下的文件:
结果803×345 23.6 KB
自己拼接一下就行了,可以人工来做或者用Codex之类的vibe一个小脚本,甚至直接让Codex给你拼接也行
en 2 zh
其实转MD是最麻烦的一步,后面都好搞,翻译用LLM来做就行,整体思路就是分段然后一段段丢给大模型
比如10自然段为一个整体,每次翻译后写入文本,然后叠起来
用Codex Vibe了一个脚本(pwsh)
param(
[Parameter(Mandatory = $true)]
[Alias("i")]
[string]$InFile,
[Parameter(Mandatory = $true)]
[Alias("o")]
[string]$Output,
[Alias("b")]
[int]$BatchSize = 10
)
$ErrorActionPreference = "Stop"
function Load-DotEnv {
param(
[string]$Path = ".env"
)
if (-not (Test-Path -Path $Path -PathType Leaf)) {
Write-Host "Warning: .env file not found, relying on system environment variables"
return
}
Get-Content -Path $Path | ForEach-Object {
$line = $_.Trim()
if ([string]::IsNullOrWhiteSpace($line)) { return }
if ($line.StartsWith("#")) { return }
$idx = $line.IndexOf("=")
if ($idx -lt 1) { return }
$key = $line.Substring(0, $idx).Trim()
$value = $line.Substring($idx + 1).Trim()
if (-not [string]::IsNullOrWhiteSpace($key)) {
[System.Environment]::SetEnvironmentVariable($key, $value, "Process")
}
}
}
function Split-IntoParagraphs {
param(
[string]$Text
)
# 统一换行符为 `\n`
$normalized = $Text -replace "`r`n", "`n"
# 按两个换行拆分
$rawParagraphs = $normalized -split "`n`n"
$paragraphs = @()
foreach ($p in $rawParagraphs) {
$trimmed = $p.Trim()
if (-not [string]::IsNullOrWhiteSpace($trimmed)) {
$paragraphs += $trimmed
}
}
return ,$paragraphs
}
function Initialize-OutputFile {
param(
[string]$OutputPath
)
# 创建或截断输出文件
[System.IO.File]::Create($OutputPath).Dispose()
}
function Append-TranslationBatch {
param(
[string]$TranslatedBatch,
[string]$OutputPath
)
# 统一将批次中的换行符规范为 CRLF
$normalized = $TranslatedBatch.Replace("`r`n", "`n").Replace("`n", "`r`n")
# 末尾加两个 CRLF 分隔批次
Add-Content -Path $OutputPath -Value ($normalized + "`r`n`r`n")
}
function Translate-Text {
param(
[string]$Text,
[string]$Model,
[string]$BaseUrl,
[string]$ApiKey
)
# 系统提示:说明翻译要求
$systemPrompt = @"
你是一个专业的翻译助手,请将英文文本翻译成中文。保持原文的技术术语和格式不变,只翻译自然语言部分。翻译对象是markdown格式,如果有不符合md格式(比如代码块没有用对应的格式)的请你修正,英文的参考文献请保持不翻译,你只能输出翻译后的文本,不能输出其他内容。
"@
$userPrompt = "请翻译以下英文文本为中文:`n`n$Text"
$body = @{
model = $Model
temperature = 0.3
max_tokens = 8000
messages = @(
@{
role = "system"
content = $systemPrompt
},
@{
role = "user"
content = $userPrompt
}
)
}
$uri = ($BaseUrl.TrimEnd("/") + "/chat/completions")
try {
$response = Invoke-RestMethod `
-Method Post `
-Uri $uri `
-Headers @{ Authorization = "Bearer $ApiKey" } `
-ContentType "application/json" `
-Body ($body | ConvertTo-Json -Depth 10) `
-TimeoutSec (5 * 60)
}
catch {
throw "API request failed: $($_.Exception.Message)"
}
if (-not $response -or -not $response.choices -or $response.choices.Count -eq 0) {
throw "received empty response from API"
}
$content = $response.choices[0].message.content
if (-not $content) {
throw "API response does not contain message.content"
}
return $content.Trim()
}
try {
# 1. 加载 .env(若存在)
Load-DotEnv
$apiKey = $env:TR_API_KEY
$baseUrl = $env:TR_API_BASE_URL
$model = $env:TR_MODEL
if ([string]::IsNullOrWhiteSpace($apiKey) -or
[string]::IsNullOrWhiteSpace($baseUrl) -or
[string]::IsNullOrWhiteSpace($model)) {
Write-Error "error: TR_API_KEY, TR_API_BASE_URL, and TR_MODEL must be set in .env or environment"
exit 1
}
Write-Host "Input file: $InFile"
Write-Host "Output file: $Output"
Write-Host "Batch size: $BatchSize"
# 2. 读取输入文件
Write-Host "Reading file..."
if (-not (Test-Path -Path $InFile -PathType Leaf)) {
Write-Error ("error reading input file {0}: file not found" -f $InFile)
exit 1
}
$content = Get-Content -Path $InFile -Raw
# 3. 切分段落
Write-Host "Splitting into paragraphs..."
$paragraphs = Split-IntoParagraphs -Text $content
$paragraphCount = $paragraphs.Count
Write-Host "Found $paragraphCount paragraphs"
# 4. 初始化输出文件
Initialize-OutputFile -OutputPath $Output
if ($paragraphCount -eq 0) {
Write-Host "No paragraphs found, nothing to translate."
exit 0
}
# 5. 批量调用 API
$successfulBatches = 0
$totalBatches = [int][math]::Ceiling($paragraphCount / [double]$BatchSize)
for ($i = 0; $i -lt $paragraphCount; $i += $BatchSize) {
$end = [math]::Min($i + $BatchSize, $paragraphCount)
$batchNum = [int]([math]::Floor($i / $BatchSize) + 1)
$range = $i..($end - 1)
$batch = $paragraphs[$range]
Write-Host ("Translating batch {0}/{1} (paragraphs {2}-{3})..." -f `
$batchNum, $totalBatches, ($i + 1), $end)
$batchText = $batch -join "`n`n"
# 翻译请求,失败时等待 30 秒重试一次
$maxAttempts = 2
$attempt = 1
$translatedBatch = $null
$translateSuccess = $false
while (-not $translateSuccess -and $attempt -le $maxAttempts) {
try {
$translatedBatch = Translate-Text -Text $batchText -Model $model -BaseUrl $baseUrl -ApiKey $apiKey
$translateSuccess = $true
}
catch {
if ($attempt -lt $maxAttempts) {
Write-Warning ("Error translating batch {0} (attempt {1}/{2}): {3}. Retrying after 30 seconds..." -f `
$batchNum, $attempt, $maxAttempts, $_.Exception.Message)
Start-Sleep -Seconds 30
$attempt++
}
else {
Write-Warning ("Error translating batch {0} (attempt {1}/{2}): {3}. Skipping." -f `
$batchNum, $attempt, $maxAttempts, $_.Exception.Message)
break
}
}
}
if (-not $translateSuccess) {
continue
}
try {
Append-TranslationBatch -TranslatedBatch $translatedBatch -OutputPath $Output
$successfulBatches++
Write-Host "Batch $batchNum translated and written to file."
}
catch {
Write-Warning "Error writing batch $batchNum to file: $($_.Exception.Message). Skipping."
continue
}
}
# 6. 总结
if ($successfulBatches -gt 0) {
Write-Host ""
Write-Host "Translation complete! Successfully translated $successfulBatches/$totalBatches batches."
Write-Host "Result saved to $Output"
}
else {
Write-Host ""
Write-Host "Translation failed. Please check your API key, network connection, and error logs."
}
exit 0
}
catch {
Write-Error $_.Exception.Message
exit 1
}
需要在同文件夹下放置一个.env,记录
TR_API_KEY=xxx
TR_API_BASE_URL=https://xxxxxxxx/v1
TR_MODEL=xxx
然后
./translator.ps1 -i <input> -o <output> -b <batch>
即可
关于翻译用的模型,建议使用指令模型而不是思考模型,这个地方盲目的用GPT、Gemini效果未必比国产模型好,就我个人的体感来说,比较建议Qwen 3.5 Plus、Qwen 3 Max或者Kimi K2 0905,相较于GPT 5.4、Gemini 3.1效果不差
利用MarkText、Typora、VS Code等工具可以将MD转换为PDF
MD 2 Page
这个就我本人来说不是很想细说,佬友们应该有不少md转换为blog的思路,也有很多现成的工具,例如mdbook、astro、hugo、hexo、vitepress、jekyll等等等,然后利用netlify、vercel、cf page、gh page等等静态网站托管服务跑起来即可
End
以上是我目前走文献翻译的流程,希望能够给大家参考
网友解答:--【壹】--:
当然是批量翻译,一百多万份pdf用mineru两周跑完上传到oss,然后再进行清洗、提取数据。如果全交给AI成本太高了
--【贰】--:
感谢分享,
--【叁】--: tutu_pink:
PDF2zh
感觉PDF2zh就不错,一直在用
--【肆】--:
感谢分享
--【伍】--:
佬友有没有试过这个幻觉翻译,作者是知乎的,他用的方案好像是转latex,我自己用下来感觉显示效果很不错:https://hjfy.top/
--【陆】--:
我也在用MATH,感觉还是得用API以及绕不开的清洗。
--【柒】--:
很有帮助
--【捌】--:
这个主要还是看什么类型的pdf。不过mineru出现脑补的情况没遇到过。我这边实际调研用起来doc2x和mineru不相上下,mineru免费当然是不二之选。doc2x也只适合少量的任务,不管是成本还是速度都不如mineru
--【玖】--:
是这样的,市面上大部分转换方案都没有比较完美的。主要是不规则的表格以及各种公式。所以需要根据工具和个人需求来清洗、修复文档。
--【拾】--:
如果文献有上传到 arXiv 的话,可以下载 TeX 源码后让 AI 翻译源码然后编译 PDF,效果非常完美。
--【拾壹】--: cc:
mineru
看你的需求是批量翻译还是一份翻译了。如果是一份翻译的话,我们就把 PDF 文件直接丢给多模态的 AI 模型,比如说比较强劲的,一定是要国内性能比较好的,比如说 gemini 然后你直接把文件丢给他。 它就会自动,你就告诉它,你自动识别文件内容和排版,然后重新整理翻译后返回。你如果想让它返回 Markdown 的话,就返回 Markdown 如果想让它返回 Word 的话,就直接告诉它基于 Python 来对这个文件进行排版,生成 Word。
如果是批量翻译的话,没得选,就只能是。 mineru 它的免费额额度还是很给力的,好像每天 2000 页,还是每个月 2000 页来着。
--【拾贰】--:
我自己用的感觉不如doc2X
mineru有时候会自己脑补
--【拾叁】--:
1、pdf转md文档首选必须是mineru,试过市面上免费的和付费的(国外的没试过)工具都没有这个转换出来的效果好。无论是数学公式还是表格方面,都很不错。
2、转换md文档之后还需要清洗文档,比如某些公式、表格还是有问题
3、翻译文本的时候不能单纯按段落分割,最好是使用DeepSeek和gemini这种上下文大的,一定要结合上下文翻译,不然中英文互译涉及专业术语会有问题
4、翻译的提示词要反复优化,不同类型的pdf文档来区分,这样翻译效果会更好,专业性更强
做pdf中英文互译基本踩过坑,还有别的不足佬友们可以指点一下
--【拾肆】--:
感谢指导!
确实,mineru 2.5的质量非常之高,不仅仅是模型本身,mineru的工作流设计在开源方案里是比较好的一档,但是自己部署OCR模型的话mineru的工作流相较于MonkeyOCR和DeepseekOCR的工作流有点难改(但是相较于paddle就好搞多了),我平时读的文献有一部分是需要自己改一下layout识别模型的参数的,比较简单的工作流好改一点
清洗文档有点疼,很多OCR模型总会搞一点有自己特点的输出,尤其是跨页代码的情况下,比如MonkeyOCR 3B Pro有时候会输出连续百个w,Mineru有时会不解析表格中的公式
至于直接喂整体上下文在有些情况下有点贵,同时考虑到国内用国外模型很多都带着一些上下文产生污染,可以走一些别的路子,比如利用GalTransl这样工具提取一个术语表带在上下文里
不过我主要是用来翻译后读文献的,十几页的文献我觉得这样足够了,毕竟主要目的是能读懂文献而不是做翻译
--【拾伍】--:
PDF2zh这个我感觉挺好用的
这两天一直在思考怎么将PDF英文文献翻译成好理解、好阅读、好查阅的中文形式,研究了一下将整个流程整理一下。
总体流程
对于一个PDF,直接对译为中文PDF在很多时候是不合适的,主要问题在于中英文表述相同意义下的字数不同,以及对公式处理不佳。考虑这一点,找到一个合适的中间格式来转可能更好。
显然markdown完美符合这个中间格式的要求,换句话说我们第一步就要将PDF转成markdown,然后因为markdown纯文本的格式,直接按段落分丢给LLM翻译就行了
而且markdown本身就有极佳的可读性,也可以借助mdbook等SSG工具转换成网页从而在各个端都能访问阅读
用流程图描述就是这样
graph LR
Start[原始 PDF 文件] --> CoreProcess
subgraph CoreProcess [核心处理流程]
direction LR
Step1[PDF 转换为 Markdown]
Step2[按段落分割纯文本,调用 LLM 进行翻译]
Result[中文 Markdown 文件]
Step1 --> Step2 --> Result
end
CoreProcess --> Final[生成网页, 实现多端访问]
PDF 2 MD
那么第一问题来了,怎么将PDF转换为md
考虑到公式、表格、图片三个要素的存在,转换方式一定是要完美保持这三个东西的,这个可以借助一些专门的OCR模型来做
我试了好几个,最后选择的是MonkeyOCR,相较于Deepseek OCR、PaddleVL OCR等几个模型,这个主要的好处是不费劲,速度和效果和Deepseek OCR差不多,比PaddleVL OCR好配置。
但是本地用这些OCR模型对显存的要求还是蛮高的,尽管模型本身只有3B参数,但是实际上跑下来大概需要12-16G显存才能运行,我使用一块V100才勉强压下来
但是也有其他方式来进行PDF转换,不少OCR提供商都有DEMO or 官方网站来进行转换,比如:dots.ocr,MinerU.
我用dots.ocr为例,上传文献之后就可以直接得到OCR后的结果,下载即可
dots.ocr DEMO1904×1710 523 KB
下载后解压完得到如下的文件:
结果803×345 23.6 KB
自己拼接一下就行了,可以人工来做或者用Codex之类的vibe一个小脚本,甚至直接让Codex给你拼接也行
en 2 zh
其实转MD是最麻烦的一步,后面都好搞,翻译用LLM来做就行,整体思路就是分段然后一段段丢给大模型
比如10自然段为一个整体,每次翻译后写入文本,然后叠起来
用Codex Vibe了一个脚本(pwsh)
param(
[Parameter(Mandatory = $true)]
[Alias("i")]
[string]$InFile,
[Parameter(Mandatory = $true)]
[Alias("o")]
[string]$Output,
[Alias("b")]
[int]$BatchSize = 10
)
$ErrorActionPreference = "Stop"
function Load-DotEnv {
param(
[string]$Path = ".env"
)
if (-not (Test-Path -Path $Path -PathType Leaf)) {
Write-Host "Warning: .env file not found, relying on system environment variables"
return
}
Get-Content -Path $Path | ForEach-Object {
$line = $_.Trim()
if ([string]::IsNullOrWhiteSpace($line)) { return }
if ($line.StartsWith("#")) { return }
$idx = $line.IndexOf("=")
if ($idx -lt 1) { return }
$key = $line.Substring(0, $idx).Trim()
$value = $line.Substring($idx + 1).Trim()
if (-not [string]::IsNullOrWhiteSpace($key)) {
[System.Environment]::SetEnvironmentVariable($key, $value, "Process")
}
}
}
function Split-IntoParagraphs {
param(
[string]$Text
)
# 统一换行符为 `\n`
$normalized = $Text -replace "`r`n", "`n"
# 按两个换行拆分
$rawParagraphs = $normalized -split "`n`n"
$paragraphs = @()
foreach ($p in $rawParagraphs) {
$trimmed = $p.Trim()
if (-not [string]::IsNullOrWhiteSpace($trimmed)) {
$paragraphs += $trimmed
}
}
return ,$paragraphs
}
function Initialize-OutputFile {
param(
[string]$OutputPath
)
# 创建或截断输出文件
[System.IO.File]::Create($OutputPath).Dispose()
}
function Append-TranslationBatch {
param(
[string]$TranslatedBatch,
[string]$OutputPath
)
# 统一将批次中的换行符规范为 CRLF
$normalized = $TranslatedBatch.Replace("`r`n", "`n").Replace("`n", "`r`n")
# 末尾加两个 CRLF 分隔批次
Add-Content -Path $OutputPath -Value ($normalized + "`r`n`r`n")
}
function Translate-Text {
param(
[string]$Text,
[string]$Model,
[string]$BaseUrl,
[string]$ApiKey
)
# 系统提示:说明翻译要求
$systemPrompt = @"
你是一个专业的翻译助手,请将英文文本翻译成中文。保持原文的技术术语和格式不变,只翻译自然语言部分。翻译对象是markdown格式,如果有不符合md格式(比如代码块没有用对应的格式)的请你修正,英文的参考文献请保持不翻译,你只能输出翻译后的文本,不能输出其他内容。
"@
$userPrompt = "请翻译以下英文文本为中文:`n`n$Text"
$body = @{
model = $Model
temperature = 0.3
max_tokens = 8000
messages = @(
@{
role = "system"
content = $systemPrompt
},
@{
role = "user"
content = $userPrompt
}
)
}
$uri = ($BaseUrl.TrimEnd("/") + "/chat/completions")
try {
$response = Invoke-RestMethod `
-Method Post `
-Uri $uri `
-Headers @{ Authorization = "Bearer $ApiKey" } `
-ContentType "application/json" `
-Body ($body | ConvertTo-Json -Depth 10) `
-TimeoutSec (5 * 60)
}
catch {
throw "API request failed: $($_.Exception.Message)"
}
if (-not $response -or -not $response.choices -or $response.choices.Count -eq 0) {
throw "received empty response from API"
}
$content = $response.choices[0].message.content
if (-not $content) {
throw "API response does not contain message.content"
}
return $content.Trim()
}
try {
# 1. 加载 .env(若存在)
Load-DotEnv
$apiKey = $env:TR_API_KEY
$baseUrl = $env:TR_API_BASE_URL
$model = $env:TR_MODEL
if ([string]::IsNullOrWhiteSpace($apiKey) -or
[string]::IsNullOrWhiteSpace($baseUrl) -or
[string]::IsNullOrWhiteSpace($model)) {
Write-Error "error: TR_API_KEY, TR_API_BASE_URL, and TR_MODEL must be set in .env or environment"
exit 1
}
Write-Host "Input file: $InFile"
Write-Host "Output file: $Output"
Write-Host "Batch size: $BatchSize"
# 2. 读取输入文件
Write-Host "Reading file..."
if (-not (Test-Path -Path $InFile -PathType Leaf)) {
Write-Error ("error reading input file {0}: file not found" -f $InFile)
exit 1
}
$content = Get-Content -Path $InFile -Raw
# 3. 切分段落
Write-Host "Splitting into paragraphs..."
$paragraphs = Split-IntoParagraphs -Text $content
$paragraphCount = $paragraphs.Count
Write-Host "Found $paragraphCount paragraphs"
# 4. 初始化输出文件
Initialize-OutputFile -OutputPath $Output
if ($paragraphCount -eq 0) {
Write-Host "No paragraphs found, nothing to translate."
exit 0
}
# 5. 批量调用 API
$successfulBatches = 0
$totalBatches = [int][math]::Ceiling($paragraphCount / [double]$BatchSize)
for ($i = 0; $i -lt $paragraphCount; $i += $BatchSize) {
$end = [math]::Min($i + $BatchSize, $paragraphCount)
$batchNum = [int]([math]::Floor($i / $BatchSize) + 1)
$range = $i..($end - 1)
$batch = $paragraphs[$range]
Write-Host ("Translating batch {0}/{1} (paragraphs {2}-{3})..." -f `
$batchNum, $totalBatches, ($i + 1), $end)
$batchText = $batch -join "`n`n"
# 翻译请求,失败时等待 30 秒重试一次
$maxAttempts = 2
$attempt = 1
$translatedBatch = $null
$translateSuccess = $false
while (-not $translateSuccess -and $attempt -le $maxAttempts) {
try {
$translatedBatch = Translate-Text -Text $batchText -Model $model -BaseUrl $baseUrl -ApiKey $apiKey
$translateSuccess = $true
}
catch {
if ($attempt -lt $maxAttempts) {
Write-Warning ("Error translating batch {0} (attempt {1}/{2}): {3}. Retrying after 30 seconds..." -f `
$batchNum, $attempt, $maxAttempts, $_.Exception.Message)
Start-Sleep -Seconds 30
$attempt++
}
else {
Write-Warning ("Error translating batch {0} (attempt {1}/{2}): {3}. Skipping." -f `
$batchNum, $attempt, $maxAttempts, $_.Exception.Message)
break
}
}
}
if (-not $translateSuccess) {
continue
}
try {
Append-TranslationBatch -TranslatedBatch $translatedBatch -OutputPath $Output
$successfulBatches++
Write-Host "Batch $batchNum translated and written to file."
}
catch {
Write-Warning "Error writing batch $batchNum to file: $($_.Exception.Message). Skipping."
continue
}
}
# 6. 总结
if ($successfulBatches -gt 0) {
Write-Host ""
Write-Host "Translation complete! Successfully translated $successfulBatches/$totalBatches batches."
Write-Host "Result saved to $Output"
}
else {
Write-Host ""
Write-Host "Translation failed. Please check your API key, network connection, and error logs."
}
exit 0
}
catch {
Write-Error $_.Exception.Message
exit 1
}
需要在同文件夹下放置一个.env,记录
TR_API_KEY=xxx
TR_API_BASE_URL=https://xxxxxxxx/v1
TR_MODEL=xxx
然后
./translator.ps1 -i <input> -o <output> -b <batch>
即可
关于翻译用的模型,建议使用指令模型而不是思考模型,这个地方盲目的用GPT、Gemini效果未必比国产模型好,就我个人的体感来说,比较建议Qwen 3.5 Plus、Qwen 3 Max或者Kimi K2 0905,相较于GPT 5.4、Gemini 3.1效果不差
利用MarkText、Typora、VS Code等工具可以将MD转换为PDF
MD 2 Page
这个就我本人来说不是很想细说,佬友们应该有不少md转换为blog的思路,也有很多现成的工具,例如mdbook、astro、hugo、hexo、vitepress、jekyll等等等,然后利用netlify、vercel、cf page、gh page等等静态网站托管服务跑起来即可
End
以上是我目前走文献翻译的流程,希望能够给大家参考
网友解答:--【壹】--:
当然是批量翻译,一百多万份pdf用mineru两周跑完上传到oss,然后再进行清洗、提取数据。如果全交给AI成本太高了
--【贰】--:
感谢分享,
--【叁】--: tutu_pink:
PDF2zh
感觉PDF2zh就不错,一直在用
--【肆】--:
感谢分享
--【伍】--:
佬友有没有试过这个幻觉翻译,作者是知乎的,他用的方案好像是转latex,我自己用下来感觉显示效果很不错:https://hjfy.top/
--【陆】--:
我也在用MATH,感觉还是得用API以及绕不开的清洗。
--【柒】--:
很有帮助
--【捌】--:
这个主要还是看什么类型的pdf。不过mineru出现脑补的情况没遇到过。我这边实际调研用起来doc2x和mineru不相上下,mineru免费当然是不二之选。doc2x也只适合少量的任务,不管是成本还是速度都不如mineru
--【玖】--:
是这样的,市面上大部分转换方案都没有比较完美的。主要是不规则的表格以及各种公式。所以需要根据工具和个人需求来清洗、修复文档。
--【拾】--:
如果文献有上传到 arXiv 的话,可以下载 TeX 源码后让 AI 翻译源码然后编译 PDF,效果非常完美。
--【拾壹】--: cc:
mineru
看你的需求是批量翻译还是一份翻译了。如果是一份翻译的话,我们就把 PDF 文件直接丢给多模态的 AI 模型,比如说比较强劲的,一定是要国内性能比较好的,比如说 gemini 然后你直接把文件丢给他。 它就会自动,你就告诉它,你自动识别文件内容和排版,然后重新整理翻译后返回。你如果想让它返回 Markdown 的话,就返回 Markdown 如果想让它返回 Word 的话,就直接告诉它基于 Python 来对这个文件进行排版,生成 Word。
如果是批量翻译的话,没得选,就只能是。 mineru 它的免费额额度还是很给力的,好像每天 2000 页,还是每个月 2000 页来着。
--【拾贰】--:
我自己用的感觉不如doc2X
mineru有时候会自己脑补
--【拾叁】--:
1、pdf转md文档首选必须是mineru,试过市面上免费的和付费的(国外的没试过)工具都没有这个转换出来的效果好。无论是数学公式还是表格方面,都很不错。
2、转换md文档之后还需要清洗文档,比如某些公式、表格还是有问题
3、翻译文本的时候不能单纯按段落分割,最好是使用DeepSeek和gemini这种上下文大的,一定要结合上下文翻译,不然中英文互译涉及专业术语会有问题
4、翻译的提示词要反复优化,不同类型的pdf文档来区分,这样翻译效果会更好,专业性更强
做pdf中英文互译基本踩过坑,还有别的不足佬友们可以指点一下
--【拾肆】--:
感谢指导!
确实,mineru 2.5的质量非常之高,不仅仅是模型本身,mineru的工作流设计在开源方案里是比较好的一档,但是自己部署OCR模型的话mineru的工作流相较于MonkeyOCR和DeepseekOCR的工作流有点难改(但是相较于paddle就好搞多了),我平时读的文献有一部分是需要自己改一下layout识别模型的参数的,比较简单的工作流好改一点
清洗文档有点疼,很多OCR模型总会搞一点有自己特点的输出,尤其是跨页代码的情况下,比如MonkeyOCR 3B Pro有时候会输出连续百个w,Mineru有时会不解析表格中的公式
至于直接喂整体上下文在有些情况下有点贵,同时考虑到国内用国外模型很多都带着一些上下文产生污染,可以走一些别的路子,比如利用GalTransl这样工具提取一个术语表带在上下文里
不过我主要是用来翻译后读文献的,十几页的文献我觉得这样足够了,毕竟主要目的是能读懂文献而不是做翻译
--【拾伍】--:
PDF2zh这个我感觉挺好用的

