منذ بضعة أسابيع، قدم لي مشرفي تحديًا لمعرفة ما إذا كان بإمكاني التوصل إلى سير عمل لمشكلة معينة نواجهها. أردنا إرسال خطابات ما قبل / ACT إلى نظام الرسائل القصيرة (نظام إدارة الطلاب) الخاص بنا، والذي كان في حالتنا هو Skyward. المشكلة التي واجهناها هي أن خطابات Pre/ACT موجودة إما في ملف PDF مجمع أو لكل ملف PDF فردي، وللدخول إلى Skyward، سنحتاج إلى ملف PDF لاسم كل طالب كرقم هويته. ولتحقيق ذلك قررت أن أكتب برنامجًا بلغة بايثون، باستخدام Streamlit لواجهة المستخدم.
دعونا نلقي نظرة على المشكلات التي يتعين علينا معالجتها، بدءًا من ملف PDF. لقد كان من المنطقي أكثر مجرد الحصول على تصدير PDF واحد مجمع للحروف، وهذا يعني أننا بحاجة إلى تقسيم التصدير المجمع إلى ملفات PDF فردية. على الرغم من أن كل حرف يتكون عادةً من صفحتين، إلا أن هذا ليس هو الحال دائمًا، لذا فإن إجراء فاصل بسيط بين كل صفحة أخرى من المرجح أن يكون عرضة للخطأ.
الإصدار الثاني كان قراءة ملف PDF الخاص بكل طالب وإعادة تسميته إلى رقم المعرف المقابل. كان هذا يعتمد في الغالب على نمط Regex الذي سحب ما أحتاجه.
نظرًا لأن هذا كان يمثل أيضًا تحديًا زمنيًا، فقد عملت مع الذكاء الاصطناعي للمساعدة في إنشاء الكود. ملحوظة: هذا ليس بديلاً عن معرفة المنطق واللغة التي تستخدمها. عند كتابة هذا باستخدام AI/LLM، استخدمت نهج سلسلة الأفكار، حيث أعطيت أجزاء صغيرة مما أردت، ثم قمت بتصحيح الأخطاء واختبار كل جزء قبل إضافة المزيد. الكود أدناه هو الكود النهائي الذي تم استخدامه، وسوف أقوم بتقسيم كل قسم إلى قسم. إذا كنت تتطلع إلى تنفيذ هذا كحل في منطقتك، فاطلع على TLDR في نهاية هذا المنشور.
هذا الجزء واضح ومباشر إلى حد ما وهو الأساس الذي يعمل عليه البرنامج.
محتوى المتطلبات.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 المجمع وإنشاء قائمة بالصفحات التي سيتم استخدامها لتقسيمها، وهذا هو الجزء الذي يتوقف على التعبير العادي وقد يحتاج إلى تغيير لموقفك.
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")بناء واجهة المستخدم
الجزء الأخير من الكود مخصص لواجهة المستخدم. 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