数週間前、私の上司は私に、私たちが抱えている特定の問題に対するワークフローを考え出せるかどうかという課題を与えました。 Pre/ACT レターを SMS (Student Management System) (私たちの場合は Skyward) に取り込みたいと考えていました。私たちが遭遇した問題は、Pre/ACT レターが一括 PDF または個別 PDF のいずれかに含まれており、Skyward にアクセスするには、各学生の名前を ID 番号として PDF にする必要があるということです。これを達成するために、UI に Streamlit を使用して、Python でプログラムを作成することにしました。
PDF から始めて、対処する必要がある問題を見てみましょう。レターの一括単一 PDF エクスポートを取得する方が合理的です。これは、一括エクスポートを個別の PDF に分割する必要があることを意味します。各レターは通常 2 ページですが、常にそうとは限りません。そのため、単純に 1 ページおきに区切るとエラーが発生しやすくなります。
2 番目の問題は、各生徒の PDF を読み取り、その名前を対応する ID 番号に変更することでした。これは主に、必要なものを引き出す正規表現パターンに依存していました。
これも時間のかかる課題だったので、AI と連携してコードの生成を支援しました。注: これは、使用しているロジックと言語を知ることに代わるものではありません。 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 + 1 < len(id_pages) else total_pages pdf_writer = PyPDF2.PdfWriter() for j in range(start_page, end_page): pdf_writer.add_page(pdf_reader.pages[j]) temp_pdf_path = output_folder / f'temp_{i}.pdf' with open(temp_pdf_path, 'wb') as output_pdf: pdf_writer.write(output_pdf) temp_pdfs.append(temp_pdf_path) progress_callback((i + 1) / len(id_pages)) # Update progress bar # Process renaming in parallel with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor: executor.map(lambda pdf_path: extract_and_rename_pdf(pdf_path, output_folder), temp_pdfs)
def 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)
次に、いくつかの短い関数があります。1 つはすべての分割 PDF を圧縮する関数 (これを内部サーバーで実行する場合)、もう 1 つは一時ファイルをクリーンアップして、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.")
起動して実行するには、次のコマンドを使用するだけです (これは 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
幼稚園から高等学校までの学校に通っている方には、これがお役に立てば幸いです。もしそうなら、拍手するか、コーヒーをおごってください。次回まで、順風と海を追ってください。
以上がSkyward 用に PDF を簡単に分割して名前変更の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。