在处理大量PDF翻译任务时,手动逐页操作显然不现实。本文介绍如何用Python + LangChain构建一个简易的PDF翻译Agent,实现自动分块、调用翻译API、合并结果的完整流程。
前言
PDF翻译自动化有几个典型痛点:
- PDF结构复杂,直接全文提取容易丢失格式
- 大模型上下文有限,长文档需要分块处理
- 翻译后需要按原结构合并,保持可读性
- 专业术语不一致,需要术语库支持
本文的方案适合有一定Python基础的开发者,代码可直接运行和扩展。
环境准备
- Python 3.10+
- 依赖库:
pip install langchain pymupdf openai requests python-dotenv
- 一个可用的翻译API(本文以OpenAI兼容接口为例,可替换为PDFTranslator API或其他大模型API)
设计思路
整个Agent的工作流程:
读取PDF → 按页/段落分块 → 术语预处理 → 调用翻译API → 术语还原 → 合并输出 → 保存为Markdown/PDF
核心组件:
| 组件 | 作用 |
|---|---|
| PyMuPDF | 提取PDF文本和页面结构 |
| LangChain | 组织翻译Chain和Prompt模板 |
| 术语库CSV | 维护专业术语标准译法 |
| 翻译API | 执行实际翻译 |
代码实现
Step 1:读取PDF并分块
import fitz # PyMuPDF
from pathlib import Path
def extract_pdf_chunks(pdf_path: str, chunk_by: str = "page") -> list[dict]:
"""按页提取PDF文本块
Args:
pdf_path: PDF文件路径
chunk_by: 分块方式,目前支持 page
Returns:
每个元素包含 page_num 和 text
"""
doc = fitz.open(pdf_path)
chunks = []
for page_num in range(len(doc)):
page = doc.load_page(page_num)
text = page.get_text("text")
chunks.append({
"page_num": page_num + 1,
"text": text.strip()
})
doc.close()
return chunks
Step 2:加载术语库
import csv
from pathlib import Path
def load_glossary(csv_path: str) -> dict:
"""加载术语库
CSV格式:source,target
"""
glossary = {}
if not Path(csv_path).exists():
return glossary
with open(csv_path, "r", encoding="utf-8") as f:
reader = csv.DictReader(f)
for row in reader:
glossary[row["source"].strip()] = row["target"].strip()
return glossary
Step 3:术语保护与还原
import uuid
def protect_terms(text: str, glossary: dict) -> tuple[str, dict]:
"""将术语替换为占位符,避免翻译时产生不一致"""
placeholder_map = {}
for source, target in glossary.items():
placeholder = f"__TERM_{uuid.uuid4().hex[:8].upper()}__"
placeholder_map[placeholder] = target
text = text.replace(source, placeholder)
return text, placeholder_map
def restore_terms(text: str, placeholder_map: dict) -> str:
"""将占位符还原为标准译法"""
for placeholder, target in placeholder_map.items():
text = text.replace(placeholder, target)
return text
Step 4:LangChain翻译Chain
import os
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from dotenv import load_dotenv
load_dotenv()
# 配置API(请替换为你的实际API地址和Key)
llm = ChatOpenAI(
model="gpt-4o-mini",
openai_api_base=os.getenv("OPENAI_API_BASE", "https://api.openai.com/v1"),
openai_api_key=os.getenv("OPENAI_API_KEY"),
temperature=0.1,
)
prompt = ChatPromptTemplate.from_messages([
("system", "你是一名专业翻译。请将用户提供的英文PDF段落翻译成中文,保持原意和语气。不要解释,只输出译文。"),
("human", "{text}")
])
translate_chain = prompt | llm
def translate_text(text: str) -> str:
"""调用LangChain Chain翻译文本"""
if not text.strip():
return ""
response = translate_chain.invoke({"text": text})
return response.content
Step 5:完整翻译流程
def translate_pdf(pdf_path: str, glossary: dict, output_path: str):
"""翻译整个PDF并保存为Markdown"""
chunks = extract_pdf_chunks(pdf_path)
results = []
for chunk in chunks:
print(f"Translating page {chunk['page_num']}...")
protected_text, placeholder_map = protect_terms(chunk["text"], glossary)
translated = translate_text(protected_text)
restored = restore_terms(translated, placeholder_map)
results.append({
"page_num": chunk["page_num"],
"translated": restored
})
# 输出为Markdown
with open(output_path, "w", encoding="utf-8") as f:
for r in results:
f.write(f"## 第{r['page_num']}页\n\n")
f.write(r["translated"])
f.write("\n\n---\n\n")
print(f"Done. Output saved to {output_path}")
Step 6:运行示例
if __name__ == "__main__":
glossary = load_glossary("glossary.csv")
translate_pdf(
pdf_path="sample.pdf",
glossary=glossary,
output_path="translated_sample.md"
)
术语库CSV示例
source,target
neural network,神经网络
machine learning,机器学习
SSL certificate,SSL证书
warranty period,保修期
进阶方向
这个基础Agent可以继续扩展:
- 按段落分块:对于页数少但单页内容多的文档,按段落分块比按页更精细。
- 上下文增强:在翻译每个块时,注入文档摘要或前面块的关键信息,提升连贯性。
- 双语对照输出:生成原文-译文对照格式,方便校对。
- 集成PDFTranslator API:如果你需要保留原始PDF排版,可以将翻译后的文本交给支持格式保留的API二次处理。
- 异步并发:用asyncio或线程池并行翻译多个块,提升速度。
总结
用LangChain构建PDF翻译Agent的核心价值,是把"提取-翻译-合并"的流程标准化。术语库的加入则解决了机器翻译中术语不一致的常见问题。
对于开发者来说,这套方案可以作为企业内部文档翻译 pipeline 的基础模块;对于个人用户,直接调用PDFTranslator这类保留格式的工具可能更省事。两者可以根据实际需求组合使用。
标签:PDF翻译、Python自动化、LangChain、AI翻译、开发者工具

391

被折叠的 条评论
为什么被折叠?



