news 2026/8/14 4:31:55

用 tqdm+requests 打造支持进度条的PDF翻译CLI工具

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用 tqdm+requests 打造支持进度条的PDF翻译CLI工具

前言

最近在做一个批量翻译任务:把一个 200 多页的英文论文 PDF 翻译成中文,然后做对照阅读。这个过程中,我希望能看到翻译进度——一个 200 页的 PDF,如果只是黑盒等 5 分钟,体验是糟糕的。

requests适合发请求,tqdm适合做进度条,把它们组合起来做一个 CLI 工具,既能给真实用户用,也能集成到后续自动化流水线里。

本文给出一个完整的、可直接运行的 Python CLI 脚本。代码我已经用了两周,生产场景够用。

环境准备

  • Python 3.10+
  • 依赖:pip install requests tqdm
pipinstallrequests tqdm

思路概述

整体流程:

  1. requests上传 PDF 到 PDFTranslator API
  2. 轮询任务状态(类似异步任务模式)
  3. tqdm显示总体进度
  4. 下载翻译结果到本地

PDFTranslator 提供了创建任务 → 轮询 → 下载的标准异步任务 API,这正好适合进度条场景。

实现步骤

Step 1: 上传 PDF 并创建翻译任务

importrequestsfrompathlibimportPath API_BASE="https://api.pdftranslator.org/v1"defcreate_translation_task(pdf_path:str,target_lang:str="zh-CN")->str:"""创建翻译任务,返回 task_id Args: pdf_path: 待翻译的 PDF 文件路径 target_lang: 目标语言代码,如 zh-CN / en / es / fr Returns: task_id: 翻译任务 ID,后续用于轮询结果 """url=f"{API_BASE}/translate/create"headers={"Authorization":"Bearer YOUR_API_KEY"}# 替换为你的 API Keywithopen(pdf_path,"rb")asf:files={"file":(Path(pdf_path).name,f,"application/pdf")}data={"target_lang":target_lang,"preserve_format":"true"}response=requests.post(url,headers=headers,files=files,data=data,timeout=60)response.raise_for_status()returnresponse.json()["task_id"]

Step 2: 轮询任务状态

importtimedefwait_for_task(task_id:str,poll_interval:float=2.0)->dict:"""轮询任务状态直到完成 Args: task_id: 翻译任务 ID poll_interval: 轮询间隔(秒) Returns: 任务完成时的完整响应 JSON """url=f"{API_BASE}/translate/status/{task_id}"headers={"Authorization":"Bearer YOUR_API_KEY"}whileTrue:resp=requests.get(url,headers=headers,timeout=30).json()status=resp.get("status")ifstatus=="completed":returnrespifstatus=="failed":raiseRuntimeError(f"翻译失败:{resp.get('error')}")# pending / processing 状态,继续轮询time.sleep(poll_interval)

Step 3: 整合 tqdm 显示进度条

fromtqdmimporttqdmimportsysdeftranslate_with_progress(pdf_path:str,output_path:str,target_lang:str="zh-CN"):"""带进度条的翻译流程 进度条 0-30%:上传 + 创建任务 进度条 30-90%:等待处理 进度条 90-100%:下载结果 """bar=tqdm(total=100,desc="翻译PDF",unit="%",file=sys.stdout)try:# 1. 创建任务 (0% -> 30%)bar.update(5)task_id=create_translation_task(pdf_path,target_lang)bar.update(25)# 2. 轮询直到完成 (30% -> 90%)# 假设根据页数估算"处理进度",这里是简化版page_count=_estimate_pages(pdf_path)last_progress=30whileTrue:result=wait_for_task(task_id,poll_interval=2.0)current_progress=result.get("progress",50)# 将处理进度映射到 30-90 区间mapped=30+int(current_progress*0.6)ifmapped>last_progress:bar.update(mapped-last_progress)last_progress=mappedifresult["status"]=="completed":break# 3. 下载结果 (90% -> 100%)download_url=result["download_url"]withrequests.get(download_url,stream=True,timeout=120)asr:r.raise_for_status()withopen(output_path,"wb")asf:forchunkinr.iter_content(chunk_size=8192):f.write(chunk)bar.update(0.5)# 视觉补偿bar.update(100-last_progress)# 补满到 100%bar.set_description(f"✅ 完成:{output_path}")finally:bar.close()def_estimate_pages(pdf_path:str)->int:"""快速估算PDF页数(通过文件大小粗估)"""size_mb=Path(pdf_path).stat().st_size/(1024*1024)returnint(size_mb*50)# 粗估:每页约 20KB

Step 4: CLI 入口(用 argparse)

importargparsedefmain():parser=argparse.ArgumentParser(description="带进度条的 PDF 翻译 CLI")parser.add_argument("pdf",help="待翻译的 PDF 文件路径")parser.add_argument("-o","--output",help="输出路径,默认与输入同名 _translated.pdf")parser.add_argument("-l","--lang",default="zh-CN",help="目标语言代码,默认 zh-CN。可选:en, es, fr, de, ja, ko")args=parser.parse_args()output=args.outputorstr(Path(args.pdf).with_name(Path(args.pdf).stem+"_translated.pdf"))translate_with_progress(args.pdf,output,args.lang)print(f"\n✅ 翻译完成,已保存到:{output}")if__name__=="__main__":main()

完整脚本

把上面所有步骤合并到一个文件translate_pdf.py:

#!/usr/bin/env python3# -*- coding: utf-8 -*-""" translate_pdf.py - 带进度条的 PDF 翻译 CLI 工具 用法: python translate_pdf.py report.pdf -l en -o report_en.pdf """importargparseimportsysimporttimefrompathlibimportPathimportrequestsfromtqdmimporttqdm API_BASE="https://api.pdftranslator.org/v1"API_KEY="YOUR_API_KEY"# 替换为你的 API Keydefcreate_translation_task(pdf_path:str,target_lang:str)->str:"""创建翻译任务"""url=f"{API_BASE}/translate/create"headers={"Authorization":f"Bearer{API_KEY}"}withopen(pdf_path,"rb")asf:files={"file":(Path(pdf_path).name,f,"application/pdf")}data={"target_lang":target_lang,"preserve_format":"true"}resp=requests.post(url,headers=headers,files=files,data=data,timeout=60)resp.raise_for_status()returnresp.json()["task_id"]defwait_for_task(task_id:str,poll_interval:float=2.0)->dict:"""轮询任务状态"""url=f"{API_BASE}/translate/status/{task_id}"headers={"Authorization":f"Bearer{API_KEY}"}whileTrue:resp=requests.get(url,headers=headers,timeout=30).json()status=resp.get("status")ifstatus=="completed":returnrespifstatus=="failed":raiseRuntimeError(f"翻译失败:{resp.get('error')}")time.sleep(poll_interval)defdownload_result(download_url:str,output_path:str,bar:tqdm):"""流式下载翻译结果"""withrequests.get(download_url,stream=True,timeout=120)asr:r.raise_for_status()withopen(output_path,"wb")asf:forchunkinr.iter_content(chunk_size=8192):ifchunk:f.write(chunk)bar.update(0.3)deftranslate_with_progress(pdf_path:str,output_path:str,target_lang:str):"""主流程"""bar=tqdm(total=100,desc="翻译中",unit="%")task_id=create_translation_task(pdf_path,target_lang)bar.update(30)# 上传完成try:whileTrue:result=wait_for_task(task_id,poll_interval=2.0)progress=result.get("progress",50)current=30+int(progress*0.6)bar.n=min(90,current)bar.refresh()ifresult["status"]=="completed":breakdownload_result(result["download_url"],output_path,bar)bar.n=100bar.refresh()finally:bar.close()defmain():parser=argparse.ArgumentParser(description="带进度条的 PDF 翻译 CLI")parser.add_argument("pdf",help="待翻译 PDF")parser.add_argument("-o","--output")parser.add_argument("-l","--lang",default="zh-CN")args=parser.parse_args()output=args.outputorstr(Path(args.pdf).with_name(Path(args.pdf).stem+"_translated.pdf"))translate_with_progress(args.pdf,output,args.lang)print(f"\n✅ 已保存:{output}")if__name__=="__main__":main()

运行效果

$ python translate_pdf.py research.pdf-lzh-CN 翻译中:100%|████████████████████████|100/100[04:47<00:00,2.87s/%]✅ 已保存: research_translated.pdf

进度条下方会显示当前进度,翻译总耗时 5 分钟以内。

工程化建议

如果你打算把这个工具放到生产环境,有几点建议:

  1. 重试机制:网络中断时增加tenacity重试
  2. 日志:用logging替代 print,方便排查
  3. 并发批量:concurrent.futures.ThreadPoolExecutor一次处理多个 PDF
  4. 配置文件:API Key 用环境变量,不写死在代码里
  5. 错误处理:对 PDF 损坏、文件过大等情况做用户友好提示

总结

进度条看似是"小事",但对长时间任务的用户体验至关重要。tqdm几行代码就解决问题,值得纳入工具脚本的标配。

完整脚本可以扩展为:

  • 批量翻译整个目录
  • 集成到 Celery 异步任务队列
  • 提供 Web UI(Tornado / FastAPI + 后台任务)

下一步建议:如果你也有批量翻译需求,可以扩展为 Web 界面,让非技术同事也能用。


标签:Python、PDF翻译、tqdm、CLI工具、AI翻译

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/14 4:31:04

从纯方位无源定位到协同控制:无人机编队数学建模核心解析

1. 赛题回顾与核心难点定位2022年的全国大学生数学建模竞赛B题&#xff0c;题目是“无人机遂行编队飞行中的纯方位无源定位”。这个题目一出来&#xff0c;当时就在参赛圈里引起了不小的讨论。它不像一些纯优化或者数据分析题那样有明确的套路可循&#xff0c;而是把一个非常前…

作者头像 李华
网站建设 2026/8/14 4:26:23

数学建模竞赛资源优化配置:从模型构建到算法求解的完整指南

1. 赛题核心定位与价值分析 2025年全国大学生数学建模竞赛的B题&#xff0c;从题目公布的那一刻起&#xff0c;就在各大高校的建模圈子里引发了不小的讨论。作为一名带过好几届队伍的“老教练”&#xff0c;我的第一感觉是&#xff1a;这道题出得非常“正”&#xff0c;它没有刻…

作者头像 李华
网站建设 2026/8/14 4:26:15

大模型概念激活原理:从Transformer架构到高效提示词设计

1. 项目概述&#xff1a;从“一万字”到“一个名字”的认知跃迁在提示词工程这个领域里摸爬滚打久了&#xff0c;你一定会遇到一个让人既兴奋又困惑的现象&#xff1a;有时候&#xff0c;你绞尽脑汁写了几百上千字的详细描述&#xff0c;试图让AI理解一个复杂概念&#xff0c;结…

作者头像 李华
网站建设 2026/8/14 4:24:28

EMR Serverless StarRocks 2.2.0:一条SQL实现多模态数据智能检索

1. 项目概述&#xff1a;当数据湖遇上向量引擎&#xff0c;一次查询的范式革命最近在数据圈子里&#xff0c;阿里云EMR Serverless StarRocks&#xff08;内部代号Stella 2.2.0&#xff09;的发布&#xff0c;实实在在地让我这个老数据工程师兴奋了一把。这可不是一次简单的版本…

作者头像 李华
网站建设 2026/8/14 4:23:46

Easy Code插件深度定制:从代码生成器到团队开发规范基础设施

1. 从“一键生成”到“深度定制”&#xff1a;重新认识Easy Code插件如果你是一名Java开发者&#xff0c;并且日常使用IntelliJ IDEA作为主力开发工具&#xff0c;那么“Easy Code”这个名字你大概率不会陌生。在各大技术社区和插件推荐榜单里&#xff0c;它常常被冠以“MyBati…

作者头像 李华