网易首页 > 网易号 > 正文 申请入驻

如何把翻译效果做到一流——基于大模型的翻译系统「下」

0
分享至

上文见>>

论文翻译系统核心代码

核心步骤


  1. 首先读取目标PDF中的所有文字块,将其保存在指定Json。

  2. 将目标PDF中的文字块全部删除,保留一个不包含文字块的PDF模板文件。

  3. 对Json进行处理,基于Json中的文本内容进行翻译操作,保存为新Json。

  4. 基于Json,将文本块按照原格式排版写入PDF模板文件。

extract_pdf_text_to_json函数

extract_pdf_text_to_json函数来提取PDF中的文本块。

def extract_pdf_text_to_json(input_pdf_path, output_json_path, default_fontname = "Helvetica"):
"""
从指定的PDF中提取文本信息,并将其保存为JSON文件。
:parameters:
- input_pdf_path (str): Path to the input PDF file.
- output_json_path (str): Path where the output JSON file should be saved.
"""
with fitz.open(input_pdf_path) as input_pdf:
# 初始化一个列表以保存提取的文本数据
text_data = []
# 迭代输入PDF中的每一页
for page_num in range(len(input_pdf)):
input_page = input_pdf[page_num]
text_dict = input_page.get_text("dict")
# 处理此页面上的文本块
for block in text_dict["blocks"]:
if block["type"] == 0: # 文本块类型为0
# Extract text from each line in the block
block_text = "\n".join(" ".join(span["text"] for span in line["spans"]) for line in block["lines"])
sizes = [span["size"] for line in block["lines"] for span in line["spans"]]
size_counter = collections.Counter(sizes)
common_size = size_counter.most_common(1)[0][0] if sizes else None
colors = [span["color"] for line in block["lines"] for span in line["spans"]]
color_counter = collections.Counter(colors)
common_color = color_counter.most_common(1)[0][0] if colors else None
final_color = rgb_to_fitz_color(common_color)
block_entry = {
"page": page_num,
"rect": list(fitz.Rect(block["bbox"])),
"text": block_text,
"size": common_size,
"color": final_color,
"fontname": block["fontname"] if "fontname" in block else default_fontname,
}
text_data.append(block_entry)
【更多更详尽的代码 见大模型3期】

此函数不仅提取了文本内容,还保留了每个文本块的页码、位置、字体大小、颜色

等关键信息。这些信息被保存为JSON格式,为后续的翻译和重组过程提供了必要的结构数据。

remove_text_from_pdf函数

为了保持原PDF中的非文本元素(如图像、图表等),我们实现了remove_text_from_pdf函数,用来创建了一个仅包含非文本元素的PDF模板。

def remove_text_from_pdf(input_pdf_path, output_pdf_path):
"""
从PDF文件中删除所有文本,并将结果保存为PDF模板。
:parameters:
- input_pdf_path (str): Path to the input PDF file.
- output_pdf_path (str): Path where the output PDF template should be saved.
"""
doc = fitz.open(input_pdf_path)
# 遍历文档的每一页
for page in doc:
# 获取页面上的所有文字块
text_dict = page.get_text("dict")
# 遍历所有文字块
for block in text_dict["blocks"]:
if block["type"] == 0: # 文本块类型为0
# 获取文字块位置
rect = fitz.Rect(block["bbox"])
# 添加红线注释
page.add_redact_annot(rect)


# 应用并清除标记的内容,实际删除文本
page.apply_redactions()


# 保存修改后的PDF文件
doc.save(output_pdf_path)
doc.close()

这个函数通过添加红线注释并应用编辑来删除所有文本,同时保留其他元素,从而创建一个可供后续使用的PDF模板。

get_blocks_text_translated函数

为了确保翻译的一致性和效率,采用了单文本块并发翻译的策略。当然也曾尝试实现过多文本块组合翻译的策略,但拆分存在一定的错误率,会出现翻译前后文本数量不一致的情况,不稳定。

def get_blocks_text_translated(blocks_text_list, model_name):
simple_translate_prompt = """
你是一名资深的翻译工作者,你的目标是帮助用户将指定文本内容翻译为中文。
你必须满足以下要求:
- 如果需要翻译的文本内容为空,则无需输出任何内容。请不要输出抱歉等任何说明和描述。
- 下面为一些翻译时参考的角度,你需要考虑这些角度来确保翻译的准确性。
- "准确性":翻译内容需要尽可能准确地表达原文的意思。
- "数字、公式、特殊符号与网址":如果翻译内容涉及到数字、公式、特殊符号与网址,你无需对数字、公式、特殊符号与网址进行翻译,仅确保数字、公式、特殊符号与网址不变即可。
- "术语":在专业领域中,很多词汇有特定的含义,需要确保这些术语被准确地翻译。
- "语境":理解原文的语境对于准确翻译非常重要。你需要需要确认具体语境。
【更多更详尽的代码 见大模型3】
下面为指定需要翻译的文本内容,你无需返回原文,无需给出任何说明和描述,仅提供最终翻译结果。
{content}
"""
# 初始化用于存储翻译后的文本块的列表
translated_blocks_text_list = []
print(blocks_text_list)
# 创建一个线程池
with concurrent.futures.ThreadPoolExecutor(max_workers=24) as executor:
# 使用map函数并发执行get_res函数
results = executor.map(lambda block_text: get_res(simple_translate_prompt.format(content=block_text), model_name), blocks_text_list)
# 遍历结果
for result in results:
try:
# 获取翻译响应
translate_response = result.choices[0].message.content
# 将翻译后的响应添加到translated_blocks_text_list列表中
translated_blocks_text_list.append(translate_response)
except Exception as exc:
print(f"An error occurred while translating: {exc}")

这个函数使用预定义的翻译提示模板,为每个文本块生成翻译请求。然后,它使用get_res函数并发调用大模型API进行翻译。这种方法既保证了翻译质量,又提高了处理效率。为了提高整体翻译效率,采用了并发处理机制。在翻译阶段,使用Python的concurrent.futures模块实现了并发API调用,显著减少了处理大型文档的时间。

update_translated_json函数

翻译完成后,我们使用update_translated_json函数将翻译结果整合到原始的JSON结构中。这个函数首先校验翻译后的文本块数量与原始文本块数量是否一致,校验通过后会将翻译后的文本更新到JSON结构中,保持了原始PDF的结构信息。

def update_translated_json(json_path, new_json_path, blocks_text_count, translated_blocks_text_list):
if len(translated_blocks_text_list) != blocks_text_count:
raise ValueError("The number of translated text blocks does not match the original text blocks.")
# 打开并加载JSON文件
with open(json_path, 'r', encoding='utf-8') as f:
text_data = json.load(f)
# 遍历每个文本块
for i, block in enumerate(text_data):
block['text'] = translated_blocks_text_list[i]
print(block['text'])
# 将更新后的文本数据保存为JSON文件
with open(new_json_path, "w", encoding='utf-8') as f2:
json.dump(text_data, f2, indent=2, ensure_ascii=False)

write_text_to_pdf_from_json函数

使用write_text_to_pdf_from_json函数将翻译后的文本写入之前生成的PDF模板。

def write_text_to_pdf_from_json(input_json_path, template_pdf_path, output_pdf_path, ttf_path=None):
"""
从JSON文件中读取文本信息并将其写入指定的PDF模板中。
:parameters:
- input_json_path (str): Path to the input JSON file containing text data.
- template_pdf_path (str): Path to the template PDF file.
- output_pdf_path (str): Path where the output PDF file should be saved.
- default_fontname (str, optional): Default font name to use for the text in the output PDF. Defaults to "Helvetica".
- ttf_path (str, optional): Path to the ttf file to be used as font. If not provided, default_fontname will be used.
"""
# Load text data from the JSON file
with open(input_json_path, "r",encoding="utf-8") as json_file:
text_data = json.load(json_file)


# 使用模板文件
output_pdf = fitz.open(template_pdf_path)


# 遍历文本数据
for block in text_data:
# 如果需要,将新页面添加到输出PDF
while block["page"] >= len(output_pdf):
output_pdf.new_page()


output_page = output_pdf[block["page"]]

if ttf_path is not None:
default_fontname = "Sourcehan"
output_page.insert_font(fontname=default_fontname,fontfile=ttf_path)
rect = fitz.Rect(*block["rect"])


rect_height = block["rect"][3] - block["rect"][1]
rect_width = block["rect"][2] - block["rect"][0]
rect_gradient = rect_height / rect_width
# 计算文本块的宽高比
if rect_gradient < 10:
bbox = -1
# 尝试将文本插入矩形框,判断是否能正常插入,通过减小字体的尺寸,直到可以正常插入为止
while bbox <= 0:
bbox = output_page.insert_textbox(
rect,
block["text"],
fontname=default_fontname,
fontsize=block["size"],
color=block["color"],
align=fitz.TEXT_ALIGN_LEFT, # 左对齐
)
block["size"] -= 0.5
【更多更详尽的代码 见大模型3】
# 保存新的PDF
output_pdf.save(output_pdf_path)
output_pdf.close()

该重组函数实现了以下关键功能:根据JSON中的页码信息,确保输出PDF有足够的页面;支持自定义字体文件的使用;根据文本块的位置信息,将翻译后的文本精确插入到对应位置;动态调整字体大小,以适应不同语言间可能存在的文本长度差异;处理特殊情况,如arxiv的垂直文本的旋转插入。

部分优化过程

文本写入矩形框时超出范围

问题描述:通过insert_text方法将文本信息写入PDF中,会导致文本超出原本矩形框范围。

方案一:以文本块的高度来比较,如果插入后bbox是小于0的,则表示插入是失败的,如果是大于或等于0,则表示插入成功

bbox = -1
while bbox < 0:
bbox = output_page.insert_textbox(
rect,
block["text"],
fontname=default_fontname,
fontsize=block["size"],
color=block["color"],
align=fitz.TEXT_ALIGN_LEFT, # 左对齐
)
block["size"] -= 0.5

此方案仍有问题,部分标题的字会变得非常小,原因是本身一行的字会生成两行的,因此会把字变得很小。

故还需解决标题换行的问题。

如果一个block有多个行,从第二行开始,判断该行和上一行的纵坐标是否一致,如果一致则用空格进行拼接,否则用换行符进行拼接。

for i,line in enumerate(block["lines"]):
span_text = ''
for span in line["spans"]:
span_text = span_text + span["text"].strip()
if i == 0:
block_text = block_text + span_text
if i > 0:
# 解决标题换行的代码,判断当前行的纵坐标与上一行的纵坐标是否一致
if block["lines"][i-1]["spans"][-1]['origin'][1] == block["lines"][i]["spans"][0]['origin'][1]:
block_text = block_text + ' ' + span_text

对纵向文本的写入问题

一般论文中的纵向文本为论文首页左侧的信息。初步方案通过判断纵向文本的高度是否大于300作为依据。

原代码:

if block["rect"][3] - block["rect"][1] < 300:

部分文档还是有问题

优化方案

计算rect的高宽比,大于10的直接插入文本,小于10的则对文本进行旋转插入。

rect_height = block["rect"][3] - block["rect"][1]
rect_width = block["rect"][2] - block["rect"][0]
rect_gradient = rect_height / rect_width
# 计算文本块的宽高比
if rect_gradient < 10:
bbox = -1
while bbox < 0:
bbox = output_page.insert_textbox(
rect,
block["text"],
fontname=default_fontname,
fontsize=block["size"],
color=block["color"],
align=fitz.TEXT_ALIGN_LEFT, # 左对齐
)
block["size"] -= 0.5
【更多更详尽的代码 见大模型3】

不足与优化方向

尽管该系统在文档翻译领域取得了显著成果,但仍存在一些局限性。对于复杂结构的PDF文档,如包含大量图表、公式或特殊字体的文档,解析精度可能不足。此外,虽然采用了并发翻译策略,但可能导致上下文关联的文本块之间的翻译不够连贯。对于数学公式、化学式等特殊内容,当前系统可能无法准确识别和保留其结构。在专业领域的文档翻译中,系统也可能面临无法准确理解和翻译特定术语的挑战。

基于当前系统的实现和存在的局限性,有以下几个可能的发展方向:

  • 增强PDF解析能力:探索更先进的PDF解析库或开发专有解析模块,提高对复杂PDF文档结构和元数据的解析精度。同时,开发专门的图表和公式识别模块,确保这些特殊元素在翻译过程中得到正确处理和还原。

  • 优化翻译质量:实现基于上下文的分块策略,确保语义相关的文本块能够一起被翻译,提高翻译的连贯性。引入Reflection机制,允许模型对自己的翻译结果进行反思和修正,进一步提高翻译质量。此外,开发专门的术语库管理系统,允许用户或组织创建和维护专属术语库,确保特定领域词汇的一致性和准确性。

  • 扩展系统功能:支持更多语言对的翻译,如中译英、日译中等,扩大系统的应用范围。开发OCR(光学字符识别)模块,使系统能够处理扫描版PDF或图片格式的文档。实现实时翻译预览功能,允许用户在翻译过程中查看和编辑部分翻译结果。

  • 提高系统性能:优化并发处理机制,探索更高效的任务调度算法,进一步提高系统的翻译速度。实现智能缓存机制,对常见文本段落或术语进行缓存,减少重复翻译的计算开销。探索模型压缩和量化技术,降低系统资源需求,提高翻译效率。

更多内容见七月在线「大模型项目开发线上营 第3期

↓↓↓扫码了解详情/抢购↓↓↓

课程咨询可找苏苏老师VX:julyedukefu008或七月在线其他老师

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
就在刚刚,39家A股上市公司发布重大利好 利空消息,看看都有哪些?

就在刚刚,39家A股上市公司发布重大利好 利空消息,看看都有哪些?

股市皆大事
2026-01-19 18:34:48
U23国足VS越南,开球时间变晚,裁判非西亚,越足协发高额赢球奖

U23国足VS越南,开球时间变晚,裁判非西亚,越足协发高额赢球奖

体育大学僧
2026-01-19 10:57:07
男生考上北大被父亲暴打,走投无路报警,才知父亲真实身份

男生考上北大被父亲暴打,走投无路报警,才知父亲真实身份

纸鸢奇谭
2024-10-02 19:26:12
俄柬菲免签了,明星们却扎堆北海道

俄柬菲免签了,明星们却扎堆北海道

生活时尚导刊
2026-01-19 22:00:12
东莞地铁网络越来越密,332路,917路“最长公交”还能撑多久?

东莞地铁网络越来越密,332路,917路“最长公交”还能撑多久?

小鹿姐姐情感说
2026-01-20 00:17:33
回来了!神舟二十号以无人状态返回,带回一套衣服

回来了!神舟二十号以无人状态返回,带回一套衣服

农民日报
2026-01-19 14:35:18
快手变快播?深夜上万直播间同时"搞黄色"裸聊,年度最大网络事故

快手变快播?深夜上万直播间同时"搞黄色"裸聊,年度最大网络事故

派大星纪录片
2025-12-23 16:49:00
“我不卖酒,你也不许卖”——世俗空间被挤占的荒诞一幕

“我不卖酒,你也不许卖”——世俗空间被挤占的荒诞一幕

西域都护
2026-01-17 11:56:02
睡前吃瑞舒伐他汀有危害?劝告:多人服药方式是错的,答案来了

睡前吃瑞舒伐他汀有危害?劝告:多人服药方式是错的,答案来了

荆医生科普
2026-01-19 17:55:01
国足创造历史,亚足联公开站队!中越大战前夕,一席话期盼胜利

国足创造历史,亚足联公开站队!中越大战前夕,一席话期盼胜利

十点街球体育
2026-01-19 21:26:49
暴跌70%,一年消失32万家!曾月入5万暴利烟酒店,为何一夜崩塌?

暴跌70%,一年消失32万家!曾月入5万暴利烟酒店,为何一夜崩塌?

复转这些年
2026-01-10 23:47:01
荷兰内部开始批斗经济大臣,质问他抢夺中资安世公司时没考虑后果

荷兰内部开始批斗经济大臣,质问他抢夺中资安世公司时没考虑后果

我心纵横天地间
2025-12-09 10:47:45
三年素颜无人问,领导一句“化妆吧”,隔天全公司笑不活了!

三年素颜无人问,领导一句“化妆吧”,隔天全公司笑不活了!

夜深爱杂谈
2026-01-19 20:05:51
中美两国突然都悟到了!只要甩开中国,美国就能满世界薅羊毛

中美两国突然都悟到了!只要甩开中国,美国就能满世界薅羊毛

扶苏聊历史
2025-12-30 17:23:03
苹果官宣,NFC 全面开放!

苹果官宣,NFC 全面开放!

果粉俱乐部
2026-01-17 13:30:03
大连儿童医院一保安全身挂满玩偶,网友认出他是两年前爆火的“玩具侠”,同事:他出名后并未离开,正在上班

大连儿童医院一保安全身挂满玩偶,网友认出他是两年前爆火的“玩具侠”,同事:他出名后并未离开,正在上班

极目新闻
2026-01-19 11:15:23
如果不开心,就去看李湘这个评论区,我真的快笑趴了

如果不开心,就去看李湘这个评论区,我真的快笑趴了

一只番茄鱼
2025-10-15 08:02:26
“女儿被人骑了一圈”,浙江家长情绪崩溃:那个小男孩把她当马

“女儿被人骑了一圈”,浙江家长情绪崩溃:那个小男孩把她当马

泽泽先生
2026-01-18 21:18:06
江苏省环保集团有限公司党委书记、董事长方斌斌被查

江苏省环保集团有限公司党委书记、董事长方斌斌被查

扬子晚报
2026-01-19 18:00:00
1月20日影响市场大事件

1月20日影响市场大事件

每日经济新闻
2026-01-19 21:06:58
2026-01-20 04:44:49
七月在线
七月在线
AI与智能网联汽车职教平台
836文章数 37关注度
往期回顾 全部

科技要闻

这一仗必须赢!马斯克死磕芯片"9个月一更"

头条要闻

除吴孟达、梁小龙外 十多位周星驰电影中的配角已离世

头条要闻

除吴孟达、梁小龙外 十多位周星驰电影中的配角已离世

体育要闻

错失英超冠军奖牌,他却在德甲成为传奇

娱乐要闻

吴磊起诉白珊珊诽谤,白珊珊称被盗号

财经要闻

公章争夺 家族反目 双星为何从顶端跌落?

汽车要闻

徐军:冲击百万销量,零跑一直很清醒

态度原创

亲子
手机
家居
数码
公开课

亲子要闻

宝妈必学,孩子不懂对侵犯说不,任何人都有可能是坏人!

手机要闻

真我Neo8支持四年系统维护,新品即将发布

家居要闻

隽永之章 清雅无尘

数码要闻

荣耀手表GS 5发布:行业独家防猝筛查、23天蓝牙续航,699元

公开课

李玫瑾:为什么性格比能力更重要?

无障碍浏览 进入关怀版