OCR / app.py
F-allahmoradi's picture
Update app.py
8bec47b verified
import os
import re
import tempfile
import streamlit as st
from PIL import Image
from pdf2image import convert_from_path, pdfinfo_from_path
import pytesseract
# ----------------------------------------------------------------------
# تنظیمات اولیه
# ----------------------------------------------------------------------
ZWNJ = '\u200c'
# ----------------------------------------------------------------------
# تابع نرمال‌سازی متن فارسی
# ----------------------------------------------------------------------
def normalize_text(text: str) -> str:
if not text:
return ""
arabic_to_persian = {
'ك': 'ک', 'ي': 'ی', 'ئ': 'ی', 'أ': 'ا', 'ة': 'ه',
'ؤ': 'و', 'إ': 'ا', 'ٰ': '', 'ٔ': '', 'ّ': ''
}
for ar, pr in arabic_to_persian.items():
text = text.replace(ar, pr)
corrections = {
'پسرده': 'پرده', 'اینن': 'این', 'خلسوت': 'خلوت',
'نضورد': 'نخورد', 'سبصد': 'سیصد', 'صایون': 'صابون',
'وشد': 'شد', 'میکنند': 'می‌کنند', 'میشود': 'می‌شود',
'میکرد': 'می‌کرد', 'میکنم': 'می‌کنم', 'میکنی': 'می‌کنی',
'میکسرد': 'می‌کرد', 'میکسند': 'می‌کنند', 'اِقتصاد': 'اقتصاد',
'اِجتماع': 'اجتماع', 'اِنسان': 'انسان', 'اِمکان': 'امکان'
}
for wrong, correct in corrections.items():
text = text.replace(wrong, correct)
text = re.sub(r'\b[0-9a-zA-Z\-]+\b', '', text)
text = re.sub(r'[^\w\s\u200c\u200d\u200e\u200f\u0600-\u06FF]', ' ', text)
text = re.sub(r'\s+', ' ', text).strip()
text = re.sub(r'(می|نمی)\s+(باشد|کند|شود|روم|کنم|کنی|کنید|کنیم|رسد|گردد|دهد)',
lambda m: m.group(1) + ZWNJ + m.group(2), text)
text = re.sub(r'(ها)\s+', r'\1' + ZWNJ + ' ', text)
text = re.sub(r'\s+([؟؟،،.:!;])', r'\1', text)
return text
# ----------------------------------------------------------------------
# حذف نویز و اعداد وسط متن
# ----------------------------------------------------------------------
def remove_noise(text: str) -> str:
text = re.sub(r'\b[0-9۰-۹]+\b', '', text)
text = re.sub(r'\s+', ' ', text).strip()
return text
# ----------------------------------------------------------------------
# فرمت شبیه کتاب
# ----------------------------------------------------------------------
def format_as_book(text: str) -> str:
text = re.sub(r'\n+', '\n', text)
text = re.sub(r'(?<![.؟!])\n\s*', ' ', text)
text = re.sub(r'\s+', ' ', text).strip()
text = re.sub(r'([.؟!])\s+', r'\1\n', text)
return text
# ----------------------------------------------------------------------
# OCR از تصویر
# ----------------------------------------------------------------------
def ocr_from_image(image: Image.Image) -> str:
image = image.convert('L')
config = r'--oem 3 --psm 6 -c preserve_interword_spaces=1'
raw = pytesseract.image_to_string(image, lang='fas+eng', config=config)
text = normalize_text(raw)
text = remove_noise(text)
text = format_as_book(text)
return text
# ----------------------------------------------------------------------
# OCR از PDF (با نمایش پیشرفت)
# ----------------------------------------------------------------------
def ocr_from_pdf(pdf_path: str, start_page: int, end_page: int) -> str:
try:
info = pdfinfo_from_path(pdf_path)
total_pages = int(info["Pages"])
end_page = min(end_page, total_pages)
start_page = max(1, start_page)
if start_page > total_pages:
return "❌ شماره صفحه شروع از تعداد کل صفحات بیشتر است."
images = convert_from_path(pdf_path, dpi=300, first_page=start_page, last_page=end_page)
all_text = f"📊 استخراج صفحات {start_page} تا {end_page} از {total_pages} صفحه:\n\n"
# 🟢 نوار پیشرفت و متن وضعیت
progress_bar = st.progress(0)
status_text = st.empty()
total_to_process = len(images)
for i, img in enumerate(images):
page_num = start_page + i
status_text.text(f"در حال پردازش صفحه {page_num} از {end_page} ...")
# OCR صفحه
text = ocr_from_image(img)
all_text += f"--- صفحه {page_num} ---\n{text}\n\n"
# بروزرسانی درصد
percent = int(((i + 1) / total_to_process) * 100)
progress_bar.progress(percent)
status_text.text("✅ پردازش کامل شد.")
return all_text.strip()
except Exception as e:
return f"❌ خطا در پردازش PDF: {str(e)}"
# ----------------------------------------------------------------------
# رابط کاربری Streamlit
# ----------------------------------------------------------------------
def main():
st.set_page_config(page_title="OCR فارسی - کتابی", layout="wide")
st.markdown(
"""
<style>
body {direction: rtl; text-align: right; font-family: "Vazir", "Tahoma", sans-serif;}
textarea {
direction: rtl !important;
text-align: justify !important;
font-family: "Vazir", "Tahoma", sans-serif !important;
line-height: 1.8 !important;
white-space: pre-wrap !important;
}
</style>
""", unsafe_allow_html=True
)
st.title(" OCR فارسی - خروجی شبیه کتاب")
st.markdown("استخراج متن از **PDF** یا **تصویر** بدون اعداد و نویز وسط متن")
with st.sidebar:
st.header("⚙️ تنظیمات استخراج")
uploaded_file = st.file_uploader("📁 فایل خود را آپلود کنید (PDF، JPG، PNG)", type=["pdf","jpg","jpeg","png"])
start_page, end_page = 1, 1
tmp_path = None
if uploaded_file is not None:
file_ext = uploaded_file.name.lower().split('.')[-1]
with tempfile.NamedTemporaryFile(delete=False, suffix=f".{file_ext}") as tmp_file:
tmp_file.write(uploaded_file.getvalue())
tmp_path = tmp_file.name
if file_ext == "pdf":
try:
info = pdfinfo_from_path(tmp_path)
total_pages = int(info["Pages"])
st.success(f"📄 فایل PDF با **{total_pages} صفحه** شناسایی شد.")
extract_all = st.checkbox("✅ استخراج همه صفحات", value=True)
if not extract_all:
start_page = st.number_input("صفحه شروع", 1, total_pages, 1)
end_page = st.number_input("صفحه پایان", 1, total_pages, total_pages)
else:
start_page, end_page = 1, total_pages
except Exception as e:
st.error(f"❌ خطا در خواندن PDF: {e}")
else:
st.info("📷 فایل تصویری — تمام محتوا پردازش خواهد شد.")
# Main
if uploaded_file is not None and tmp_path:
file_ext = uploaded_file.name.lower().split('.')[-1]
if file_ext == "pdf":
if st.button("🚀 استخراج متن از PDF", use_container_width=True):
with st.spinner("در حال پردازش..."):
result = ocr_from_pdf(tmp_path, start_page, end_page)
st.markdown("### 📝 متن استخراج‌شده ")
st.text_area("📘 خروجی OCR", result, height=600)
st.download_button("📥 دانلود متن", result, file_name="extracted_text.txt")
else:
st.image(uploaded_file, caption="تصویر آپلود شده", use_column_width=True)
if st.button("🚀 استخراج متن از تصویر", use_container_width=True):
with st.spinner("در حال پردازش..."):
image = Image.open(tmp_path)
result = ocr_from_image(image)
st.markdown("### 📝 متن استخراج‌شده")
st.text_area("📘 خروجی OCR", result, height=600)
st.download_button("📥 دانلود متن", result, file_name="extracted_text.txt")
if os.path.exists(tmp_path):
os.unlink(tmp_path)
else:
st.info("📁 لطفاً یک فایل آپلود کنید.")
if __name__ == "__main__":
main()