1分钟用DeepSeek编写一个PDF转Word软件

news2025/2/27 5:03:07

一、引言

如今,在线工具的普及让PDF转Word成为了一个常见需求,常见的pdf转word工具有收费的wps,免费的有pdfgear,见下文:

PDFgear:一款免费的PDF编辑、格式转化软件-CSDN博客

还有网上在线的免费pdf转word工具smallpdf, ilovepdf, 24pdf等。然而,大部分免费的在线转换工具都存在一些严重的隐私风险——文件往往需要上传至云端进行处理,这样操作极容易泄露敏感信息。

而且,许多在线平台都要求付费才能使用更高效的服务,如wps, 迅捷pdf等,这导致很多用户在无法快捷使用转换文件的服务。

为了避免上述问题,我决定利用Python开发一款本地化的PDF批量转换为Word的软件,不仅保证文件的隐私安全,还能提供完全免费、快捷、个性化的转换服务。

更重要的是,这个项目也有助于我巩固Python编程知识,深入运用DeepSeek模型提升编程能力。

二、软件的主要功能

这款PDF转word的主要功能包括:

1. 100%离线文档转换。有效地避免信息的泄露,同时也加快了文档的处理速度。

2. 支持批量PDF转Word:软件会自动扫描选择文件夹及其子文件夹(如果勾选了相关选项),并将其中的PDF文件转换为Word文档,可以节省用法大量的时间。

3. 文件夹选择与管理:用户可以选择输入和输出文件夹,支持自定义中英文路径。

4. 进度条显示:在转换过程中,软件会实时更新进度条,显示当前文件的转换进度以及整体的转换进度。

5. 自动打开目标文件夹:转换完成后,用户可以选择是否自动打开目标文件夹,查看转换结果,以便进一步操作。

三、设计过程

在设计这款应用时,我采用了Python的tkinter图形化界面和pdf2docx库来实现文件转换功能。具体如下图:

PDF转Word界面

用户界面:界面设计以简洁易用为主。通过tkinter的标签、文本框、按钮等控件,我实现了文件夹选择、设置选项、进度条显示等功能。

PDF转Word功能:因为有现成的pdf2docx的库,我采用了这个轮来进行PDF到Word格式的转换,再加上Python的批量处理功能,要以轻松满足我的文件转换需求。

多线程与进度更新:为避免界面卡顿,我使用了threading库来将文件转换操作放入独立线程,并利用queue进行线程间通信,实时更新进度条显示。

我们在设计时,借助了DeepSeek R1的深度思考模型。先上传软件图片,然后给出指令:

软件开发提示词

为了减少错误,我们在提示词加入了让deepseek进行自我运行代码,进行调试的功能,减少用户本地测试中产生的bug。

在其回复中,我们看到它针对我的提问题也进行了回答,尤其是在指定的Python环境下进行了测试。

DeepSeek自主调试功能

经过测试,代码运行无误,但是缺少进度条功能,可能是没有识别出来,或者漏掉了,于是通过追加提问:

这里我故意打错了一个汉字,但是DeepSeek还能正确地进行理解,同时很好地解决了进度条缺失的问题。就这样,我们通过两步,不到1分钟就可以把这个一个pdf转word工具制作出来。

在开发过程中,我为DeepSeek提供了完整的开发环境,DeepSeek通过对项目需求的分析,建议我添加更多的异常处理机制,特别是在文件路径不正确或者文件损坏的情况下的处理。最终,这些改进使得程序的稳定性和用户体验都得到了显著提升。

经过多次的调试和优化,软件终于成型,并可以稳定运行。用户只需选择文件夹并点击转换按钮,程序就会自动处理所有PDF文件,最终输出为Word格式。每一步的转换进度都会实时更新,确保用户能够清晰地了解当前状态。

四、代码展示

废话不多说,直接上软件的全部代码,同时提供了一些中文注释,供大家学习使用

import os
import tkinter as tk
from tkinter import ttk,filedialog, messagebox
from pdf2docx import Converter
import threading
import queue

class PDFToWordConverter:
    def __init__(self, master):
        self.master = master
        master.title("PDF批量转Word")
        master.geometry("610x295")

        # 输入文件夹
        self.lbl_input = tk.Label(master, text="输入文件夹:")
        self.ent_input = tk.Entry(master, width=30)
        self.btn_input = tk.Button(master, text="选择", command=self.select_input)

        # 输出文件夹
        self.lbl_output = tk.Label(master, text="输出文件夹:")
        self.ent_output = tk.Entry(master, width=30)
        self.btn_output = tk.Button(master, text="选择", command=self.select_output)

        # 复选框
        self.var_subdir = tk.BooleanVar()
        self.var_open = tk.BooleanVar(value=True)
        self.chk_subdir = tk.Checkbutton(master, text="包含子文件夹", variable=self.var_subdir)
        self.chk_open = tk.Checkbutton(master, text="转换完成后打开目标文件夹", variable=self.var_open)

        # 转换按钮
        self.btn_convert = tk.Button(master, text="开始转换", command=self.start_conversion)

        # 布局
        self.lbl_input.grid(row=0, column=0, padx=10, pady=10, sticky=tk.W)
        self.ent_input.grid(row=0, column=1, padx=5, pady=10, sticky=tk.EW)
        self.btn_input.grid(row=0, column=2, padx=10, pady=10)

        self.lbl_output.grid(row=1, column=0, padx=10, pady=10, sticky=tk.W)
        self.ent_output.grid(row=1, column=1, padx=5, pady=10, sticky=tk.EW)
        self.btn_output.grid(row=1, column=2, padx=10, pady=10)

        self.chk_subdir.grid(row=2, column=1, padx=5, pady=5, sticky=tk.W)
        self.chk_open.grid(row=3, column=1, padx=5, pady=5, sticky=tk.W)

        self.btn_convert.grid(row=4, column=1, pady=10)


        # 新增进度组件
        self.progress_label = tk.Label(master, text="准备就绪")
        self.progress_bar = ttk.Progressbar(master, orient=tk.HORIZONTAL, mode='determinate')
        
        # 调整布局(新增两行)
        self.progress_label.grid(row=5, column=0, columnspan=3, padx=10, pady=5, sticky=tk.W)
        self.progress_bar.grid(row=6, column=0, columnspan=3, padx=10, pady=10, sticky=tk.EW)

        # 消息队列用于线程通信
        self.queue = queue.Queue()
        master.after(100, self.process_queue)
        
        # 配置列权重
        master.columnconfigure(1, weight=1)

    def select_input(self):
        path = filedialog.askdirectory()
        if path:
            self.ent_input.delete(0, tk.END)
            self.ent_input.insert(0, path)

    def select_output(self):
        path = filedialog.askdirectory()
        if path:
            self.ent_output.delete(0, tk.END)
            self.ent_output.insert(0, path)

    def start_conversion(self):
        # 重置进度条
        self.progress_bar['value'] = 0
        self.progress_label.config(text="正在扫描PDF文件...")
        
        input_dir = self.ent_input.get()
        output_dir = self.ent_output.get()

        if not input_dir or not output_dir:
            messagebox.showerror("错误", "请先选择输入和输出文件夹!")
            return
         # 禁用转换按钮
        self.btn_convert.config(state=tk.DISABLED)
        
        threading.Thread(target=self.convert_files, args=(input_dir, output_dir), daemon=True).start()
        
    def get_pdf_list(self, input_dir):
        pdf_list = []
        for root, dirs, files in os.walk(input_dir):
            if not self.var_subdir.get() and root != input_dir:
                continue
            for file in files:
                if file.lower().endswith('.pdf'):
                    pdf_list.append(os.path.join(root, file))
        return pdf_list
    
    def convert_files(self, input_dir, output_dir):
        self.pdf_files = self.get_pdf_list(input_dir)
        try:
            total_files = len(self.pdf_files)
            for index, pdf_path in enumerate(self.pdf_files):
                # 更新当前文件进度
                self.queue.put(("file_progress", (index+1, total_files, pdf_path)))
                
                # 构建输出路径
                relative_path = os.path.relpath(os.path.dirname(pdf_path), input_dir) if self.var_subdir.get() else ""
                output_path = os.path.join(output_dir, relative_path)
                os.makedirs(output_path, exist_ok=True)
                
                # 转换文件
                docx_path = os.path.join(output_path, f"{os.path.splitext(os.path.basename(pdf_path))[0]}.docx")
                cv = Converter(pdf_path)
                cv.convert(docx_path, progress_callback=self.update_page_progress)
                cv.close()

            self.queue.put(("complete", None))
        except Exception as e:
            self.queue.put(("error", str(e)))
    def update_page_progress(self, current, total):
        # 页面级别进度(每文件0-100%)
        progress = (current / total) * 100 if total != 0 else 0
        self.queue.put(("page_progress", progress))

    def process_queue(self):
        try:
            while True:
                msg_type, data = self.queue.get_nowait()
                
                if msg_type == "file_progress":
                    current, total, path = data
                    file_progress = (current / total) * 100
                    self.progress_bar['value'] = file_progress
                    self.progress_label.config(text=f"正在转换 {current}/{total}:{os.path.basename(path)}")
                
                elif msg_type == "page_progress":
                    # 综合进度 = 文件进度 + 页面进度/总文件数
                    current_file_progress = self.progress_bar['value']
                    page_progress = data / len(self.pdf_files)
                    self.progress_bar['value'] = current_file_progress + page_progress
                
                elif msg_type == "complete":
                    messagebox.showinfo("完成", "转换完成!")
                    if self.var_open.get():
                        os.startfile(self.ent_output.get())
                    self.btn_convert.config(state=tk.NORMAL)
                    self.progress_label.config(text="转换完成")
                
                elif msg_type == "error":
                    messagebox.showerror("错误", f"转换出错:{data}")
                    self.btn_convert.config(state=tk.NORMAL)
                    self.progress_label.config(text="转换出错")

        except queue.Empty:
            pass
        finally:
            self.master.after(100, self.process_queue)
if __name__ == "__main__":
    root = tk.Tk()
    app = PDFToWordConverter(root)
    root.mainloop()

五、注意事项与启示

文件路径问题:在处理文件时,一定要注意文件路径的正确性,尤其是在跨平台使用时,路径分隔符的差异可能会导致问题。

多线程同步:为了避免界面卡顿或响应不及时,使用线程来执行耗时任务是非常必要的。但在多线程操作中,确保线程间数据同步和UI更新是一个技术挑战。

与AI工具合作:DeepSeek的辅助对我来说至关重要。在未来的开发过程中,AI工具不仅能提升我的编程效率,还能为项目带来新的创意和解决方案。

通过这个项目,我利用DeepSeek R1模型,上传软件图片,给出提示词,让它很快地开发出来一个可以平稳运行的软件,通过与AI模型的持续会话,进一步修改和完善了软件,直至可以使用。

有了DeepSeek这样的模型,未来我们只需要想法,就可以让大模型帮我们找到解决办法,完成代码撰写任务,甚至还可以进行远程调试,最终为用户提供更加精确的代码,大大缩短了项目开发的时间,让我们体会到了大语言模型的强大。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2306694.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux】初探信号的奥秘

目录 一、引入信号: 1、什么是信号: 二、前后台进程: 三、信号的处理方式: 四、键盘数据与信号: 前言: 在Linux系统编程中,信号(Signal)是一种至关重要的进程间通信…

Ubuntu搭建esp32环境 配置打开AT指令集 websocket功能

1,搭建前提 环境搭建参考乐鑫官网给的本地编译 ESP-AT 工程方法 因为公司电脑和网络的特殊性,不能正确解析域名(仅在浏览器上可以访问) ,所以这边访问的时候改成了ssh 未了避免使用外网困难的问题,这里用…

express(node ORM) 使用 Winston 记录日志 及数据库保存日志

一、安装 npm i winston npm i winston-mysql二、 配置 winston 2.1、封装 const config require(__dirname ‘/…/config/config.json’)[env]; 先判断当前是什么环境,如果.env中没有配置,就是开发环境。接着去config/config.json中读取对应的配置。…

是德科技keysight N5173B信号发生器,是一款经济高效的仪器

是德科技keysight N5173B信号发生器安捷伦N5173B信号源 是德N5173B微波模拟信号发生器,拥有 9 kHz 至 40 GHz 的频率覆盖范围,N5173B为宽带滤波器、放大器、接收机等器件的参数测试提供了必要的信号,是一款经济高效的仪器。 N5173B特点&…

从零到一:如何用阿里云百炼和火山引擎搭建专属 AI 助手(DeepSeek)?

本文首发:从零到一:如何用阿里云百炼和火山引擎搭建专属 AI 助手(DeepSeek)? 阿里云百炼和火山引擎都推出了免费的 DeepSeek 模型体验额度,今天我和大家一起搭建一个本地的专属 AI 助手。  阿里云百炼为 …

FFmpeg视频处理入门级教程

一、FFmpeg常规处理流程 #mermaid-svg-W8X1llNEyuYptV3I {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-W8X1llNEyuYptV3I .error-icon{fill:#552222;}#mermaid-svg-W8X1llNEyuYptV3I .error-text{fill:#552222;str…

C/C++ | 每日一练 (4)

💢欢迎来到张胤尘的技术站 💥技术如江河,汇聚众志成。代码似星辰,照亮行征程。开源精神长,传承永不忘。携手共前行,未来更辉煌💥 文章目录 C/C | 每日一练 (4)题目参考答案基础容器序列容器std:…

蓝桥杯备考:贪心算法之矩阵消除游戏

这道题是牛客上的一道题,它呢和我们之前的排座位游戏非常之相似,但是,排座位问题选择行和列是不会改变元素的值的,这道题呢每每选一行都会把这行或者这列清零,所以我们的策略就是先用二进制把选择所有行的情况全部枚举…

基于 CFD 预测的机器学习第 2 部分:在 Benchmark 应用程序上使用 Stochos 预测流场

了解机器学习和 Stochos 如何彻底改变制造业的 CFD 预测。 挑战 预测复杂流体动力学场景中的流场一直是工程师和科学家面临的重大挑战。传统的计算流体动力学 (CFD) 方法需要大量的计算资源和时间,因此难以处理实时预测和大规模模拟。 此外…

批量导出数据库表到Excel

这篇文章将介绍如何批量的将多个甚至成千上万的数据库表导出为Excel文件。 准备数据 如下图是数据库里的表,我们需要将它们全部导出为excel文件,这里以SQL Server数据库为例 新增导出 打开的卢导表工具,新建数据库连接,这里以S…

力扣提升第一天

力扣提升第一天 题目链接:https://leetcode.cn/problems/design-memory-allocator/?envTypedaily-question&envId2025-02-25 一开始解题思路 暴力解决法 我奔着先从简单的写法做起,之后再想办法进行改进,心里已经预料到会出现超出时间…

uni-app 开发 App 、 H5 横屏签名(基于lime-signature)

所用插件&#xff1a;lime-signature 使用到 CSS 特性 绝对定位transform 旋转transform-origin transform 原点 复习一下定位元素&#xff08;相对定位、绝对定位、粘性定位&#xff09; 代码# <template><view class"signature-page"><view clas…

【Python】Python顺序语句经典题(四)

Python顺序语句经典练习题例题&#xff08;四&#xff09;。题目来源&#xff1a;Acwing 前三期合集&#xff1a;【Python】Python顺序语句经典题合集-CSDN博客 目录 1.最大值 题目描述 解题思路 AC代码 2.距离 题目描述 AC代码 3.燃料消耗 题目描述 AC代码 4.钞票…

03_pyqt5 + vlc 实现视频播放器

1.功能需求如图 按钮: 播放/暂停, 前进/后退, 视频上一个/下一个, 打开视频进度条: 视频进度条显示, 进度条拖拽, 音量控制按键控制: 1,2,3,4缩放画面大小, 2.方案选择 开发语言: python UI界面: pyqt5 qt_designed 设计ui布局 视频编码: python-vlc 方案说明: 视频解码可…

prometheus+node_exporter+grafana监控K8S信息

prometheusnode_exportergrafana监控K8S 1.prometheus部署2.node_exporter部署3.修改prometheus配置文件4.grafana部署 1.prometheus部署 包下载地址&#xff1a;https://prometheus.io/download/ 将包传至/opt 解压 tar xf prometheus-2.53.3.linux-amd64.tar.gz 移动到…

IDEA关闭SpringBoot程序后仍然占用端口的排查与解决

IDEA关闭SpringBoot程序后仍然占用端口的排查与解决 问题描述 在使用 IntelliJ IDEA 开发 Spring Boot 应用时&#xff0c;有时即使关闭了应用&#xff0c;程序仍然占用端口&#xff08;例如&#xff1a;4001 端口&#xff09;。这会导致重新启动应用时出现端口被占用的错误&a…

山东大学软件学院nosql实验三

实验题目&#xff1a; 用Java做简单查询(2学时) 实验内容 用API方式&#xff0c;做简单查询。 实验要求 在以下要求中选择至少2个&#xff0c;使用Java语言实现数据查询&#xff0c;最终把数据输出到前端界面。 &#xff08;1&#xff09;找出年龄小于20岁的所有学生 &…

零样本学习 zero-shot

1 是什么 2 如何利用零样本学习进行跨模态迁移&#xff1f; demo代码 安装clip pip install ftfy regex tqdm pip install githttps://github.com/openai/CLIP.git import torch import clip from PIL import Image# 加载 CLIP 模型 device "cuda" if torch.cuda.i…

《深度学习实战》第3集:循环神经网络(RNN)与序列建模

第3集&#xff1a;循环神经网络&#xff08;RNN&#xff09;与序列建模 引言 在深度学习领域&#xff0c;处理序列数据&#xff08;如文本、语音、时间序列等&#xff09;是一个重要的研究方向。传统的全连接网络和卷积神经网络&#xff08;CNN&#xff09;难以直接捕捉序列中…

mac下载MAMP6.8.1

因为mac的小皮面板没有php7.4了 链接&#xff1a;c9cc270e6961c17c.dmg官方版下载丨最新版下载丨绿色版下载丨APP下载-123云盘 鹅选一 附上大佬写的教程&#xff1a;MAMP PRO教程 - 牛奔 - 博客园