几周前,我的主管给了我一个挑战,看看我是否可以针对我们遇到的特定问题提出一个工作流程。我们希望将 Pre/ACT 信件放入我们的 SMS(学生管理系统)中,在我们的例子中是 Skyward。我们遇到的问题是,Pre/ACT 信件要么是批量 PDF,要么是单独的 PDF,要进入 Skyward,我们需要每个学生的姓名作为 ID 号的 PDF。为了实现这一目标,我决定用 Python 编写一个程序,使用 Streamlit 作为 UI。
让我们从 PDF 开始看看我们需要解决的问题。获取信件的批量单个 PDF 导出更有意义,这意味着我们需要将批量导出拆分为单独的 PDF。虽然每个字母通常有 2 页,但情况并非总是如此,因此每隔一页进行简单的分隔可能很容易出错。
第二个问题是读取每个学生的PDF并将其重命名为相应的ID Number。这主要取决于满足我需要的正则表达式模式。
由于这也是一个时间挑战,我与人工智能一起帮助生成代码。注意:这并不能替代了解您正在使用的逻辑和语言。当使用 AI/LLM 编写本文时,我使用了思维链方法,给出了我想要的小块,然后在添加更多块之前调试和测试每个块。下面的代码是最终使用的代码,我将逐节分解每个代码。如果您希望将此作为您所在地区的解决方案实施,请参阅本文末尾的 TLDR。
这部分相当简单,是程序运行的基础。
requirements.txt内容
streamlit pypdf2 fitz pymupdf
app.py 导入
import PyPDF2 import fitz # PyMuPDF import re from pathlib import Path import concurrent.futures import streamlit as st import shutil import zipfile import os
下一个代码片段涉及在批量 PDF 中查找 ID 并创建用于拆分它们的页面列表,这是取决于正则表达式的部分,可能需要根据您的情况进行更改。
def find_id_pages(input_pdf): doc = fitz.open(input_pdf) id_pages = [] id_pattern = re.compile(r'\(ID#:\s*(\d )\)') for i, page in enumerate(doc): text = page.get_text() if id_pattern.search(text): id_pages.append(i) return id_pages
正如标题所说,这是用来分割PDF的。这将使用一个函数来提取每个 PDF 的名称。您还会注意到,这会将它们并行拆分(一次最多 10 个),以提高性能。
def split_pdf(input_pdf, output_folder, progress_callback): input_path = Path(input_pdf) output_folder = Path(output_folder) output_folder.mkdir(parents=True, exist_ok=True) # Find pages with IDs id_pages = find_id_pages(input_pdf) if not id_pages: st.error("No ID pages found in the PDF.") return pdf_reader = PyPDF2.PdfReader(str(input_path)) total_pages = len(pdf_reader.pages) temp_pdfs = [] for i in range(len(id_pages)): start_page = id_pages[i] end_page = id_pages[i 1] if i 1def extract_and_rename_pdf(pdf_path, output_folder): doc = fitz.open(pdf_path) text_first_page = doc[0].get_text() # Extract ID using a regex pattern for the format (ID#: 01234) match_first_page = re.search(r'\(ID#:\s*(\d )\)', text_first_page) if match_first_page: id_value = match_first_page.group(1) new_pdf_path = output_folder / f'{id_value}.pdf' pdf_path.rename(new_pdf_path) else: new_pdf_path = output_folder / f'unknown_{pdf_path.stem}.pdf' pdf_path.rename(new_pdf_path)差不多了
接下来是几个简短的函数,一个用于压缩所有拆分的 PDF(如果您想在内部服务器上运行它),另一个用于清理任何临时文件,这样就不会出现 PII 学生信息了它不需要生存。
def zip_output_folder(output_folder, zip_name): shutil.make_archive(zip_name, 'zip', output_folder)def clean_up(output_folder, zip_name): shutil.rmtree(output_folder) os.remove(f"{zip_name}.zip")构建用户界面
最后一段代码是针对 UI 的。 Streamlit 是一个多功能的 WebUI(是的,您可以单独运行它)。经过几次尝试并考虑可用性。为了简单起见,我将其简化为上传按钮、操作按钮(即拆分)和下载按钮以获取压缩的 PDF。
# Streamlit App Portion st.title("PDF Splitter and Renamer") uploaded_file = st.file_uploader("Choose a PDF file", type="pdf") output_folder = "output_folder" if st.button("Split and Rename PDF"): if uploaded_file and output_folder: try: # Save uploaded file temporarily with open("temp_input.pdf", "wb") as f: f.write(uploaded_file.getbuffer()) progress_bar = st.progress(0) def update_progress(progress): progress_bar.progress(progress) split_pdf("temp_input.pdf", output_folder, update_progress) zip_name = "output_pdfs" zip_output_folder(output_folder, zip_name) st.success("PDF split and renamed successfully!") with open(f"{zip_name}.zip", "rb") as f: st.download_button( label="Download ZIP", data=f, file_name=f"{zip_name}.zip", mime="application/zip" ) # Remove temporary file Path("temp_input.pdf").unlink() clean_up(output_folder, zip_name) except Exception as e: st.error(f"An error occurred: {e}") else: st.error("Please upload a PDF file and specify an output folder.")TLDR 启动并运行
要启动并运行,只需使用以下命令(假设是 Linux、WSL 和 MacOS)。您可以通过访问 http://localhost:8501 来访问该应用程序。
git clone https://github.com/Blacknight318/act-to-sms.git cd act-to-sms python3 -m venv venv source venv/bin/activate pip install -r requirements.txt streamlit run app.py结束语
如果您就读于 K12 学校,我希望这对您有所帮助。如果是这样,请鼓掌或考虑给我买杯咖啡。下次再见,顺风顺水。
免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。
Copyright© 2022 湘ICP备2022001581号-3