2025, Oct 03 23:35
PyScript में pytesseract और OpenCV क्यों विफल होते हैं, और सर्वर-साइड OCR कैसे चलाएँ
जानिए PyScript में pytesseract/Tesseract और OpenCV के साथ OCR ब्राउज़र सैंडबॉक्स में क्यों टूटता है, और Flask/FastAPI या NiceGUI से सर्वर-साइड समाधान कैसे लागू करें.
OpenCV, pytesseract और pandas को मिलाकर लोकल OCR स्क्रिप्ट चलाना सीधा-सादा होता है, लेकिन वही तर्क PyScript के जरिए ब्राउज़र में ले जाना अक्सर कम स्पष्ट कारणों से विफल हो जाता है. आमतौर पर अड़चनें नेटिव Tesseract बाइनरी को कॉल करने और लोकल फाइल सिस्टम से फाइलें पढ़ने के इर्द-गिर्द सामने आती हैं. नीचे एक संक्षिप्त मार्गदर्शिका है जो दिखाती है कि PyScript में मूल तरीका क्यों टूटता है, ब्राउज़र सैंडबॉक्स क्या अनुमति देता है, और वेब फ्रंट एंड रखते हुए OCR को भरोसेमंद तरीके से चलाने के लिए समाधान को कैसे पुनर्गठित करें.
मिनिमल उदाहरण: लोकली चलता है, PyScript में टूट जाता है
नीचे दिया स्निपेट मूल व्यवहार को दोहराता है: यह किसी डायरेक्टरी में छवियों को ढूंढता है, हर फ़ाइल पर pytesseract के जरिए Tesseract चलाकर OCR करता है, और आउटपुट को DataFrame के रूप में व्यवस्थित करता है. तर्क बिल्कुल वही रखा गया है, हालांकि पहचानकर्ता जानबूझकर अलग हैं.
# main.py
import pytesseract as ocr
ocr.pytesseract.tesseract_cmd = r"Tesseract-OCR\tesseract.exe"
import os
import cv2
import pandas as pd
image_bucket = []
def harvest_text(idx):
img = cv2.imread(image_bucket[idx], 0)
binarized = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
raw = ocr.image_to_string(binarized, lang='eng', config='--psm 6')
condensed = "\n".join([ln.rstrip() for ln in raw.splitlines() if ln.strip()])
return condensed.split('\n')
def run_batch():
base_dir = f'SQL_NOTES\\'
entries = os.listdir(base_dir)
for entry in entries:
if entry.startswith("imagename"):
image_bucket.append(base_dir + entry)
idx_map = dict({0: 'image_bucket[0]', 1: 'image_bucket[1]', 2: 'image_bucket[2]', 3: 'image_bucket[3]'})
rows = ([harvest_text(k) for k in idx_map])
return pd.DataFrame(rows).T
print(run_batch())
ब्राउज़र में इसे PyScript के जरिए इस तरह चलाया जाता है.
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<title>Empty Grass</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="stylesheet" href="https://pyscript.net/releases/2025.7.3/core.css">
<script type="module" src="https://pyscript.net/releases/2025.7.3/core.js"></script>
</head>
<body>
<button id="go_ocr">Run</button>
<script type="py" config="./pyscript.toml" terminal>
from pyscript import when
@when("click", "#go_ocr")
def on_go(evt):
from main import run_batch
run_batch()
</script>
</body>
</html>
# pyscript.toml
packages = [ "pytesseract", "opencv-python", "pandas" ]
[files]
"main.py" = "main.py"
असल में समस्या क्या है, और क्यों
जड़ कारण ब्राउज़र का सुरक्षा मॉडल है. PyScript ब्राउज़र के अंदर चलता है और JavaScript जैसी ही सैंडबॉक्सिंग नियमावली अपनाता है. इसका असर बाहरी बाइनरी और फाइल सिस्टम—दोनों पर पड़ता है.
PyScript किसी बाहरी .exe प्रोग्राम को नहीं चला सकता, क्योंकि सुरक्षा कारणों से ब्राउज़र इसकी अनुमति नहीं देते.
व्यवहार में, pytesseract को लोकल executable की ओर इंगित करने वाली पंक्ति PyScript में काम नहीं करती. ब्राउज़र के भीतर से Tesseract जैसे नेटिव प्रोसेस को शुरू करने का कोई तरीका नहीं है. यही पाबंदियां उन नेटिव बाइनरी पर भी लागू होती हैं जो OpenCV और pytesseract जैसी Python पैकेजों के पीछे होती हैं.
सीधे फाइल सिस्टम तक पहुंच भी सीमित है. os.listdir से लोकल डायरेक्टरी पढ़ना अनुमति-प्राप्त नहीं है. PyScript बताता है कि उसका वर्चुअल फाइल सिस्टम कैसे काम करता है और माउंटिंग के विकल्प क्या हैं. कुछ Chromium-आधारित ब्राउज़रों में आप fs.mount के जरिए उपयोगकर्ता-संवाद विंडो से लोकल डायरेक्टरी माउंट कर सकते हैं, लेकिन तब भी लोकल .exe प्रोग्राम चलाना संभव नहीं होता. दस्तावेज़: https://docs.pyscript.net/2025.8.1/user-guide/filesystem/
संयुक्त नतीजा स्पष्ट है: ब्राउज़र आपकी डिस्क को स्वतंत्र रूप से सूचीबद्ध नहीं कर सकता और न ही नेटिव executables चला सकता है. डेस्कटॉप Python पर सामान्य दिखने वाली दो पंक्तियाँ—tesseract_cmd असाइनमेंट और डायरेक्टरी traversal—PyScript के भीतर व्यवहार्य नहीं हैं.
व्यावहारिक रास्ता: OCR को सर्वर-साइड ले जाएँ
उपाय यह है कि वेब UI ब्राउज़र में रहे, जबकि OCR निष्पादन को किसी वेब सर्वर पर स्थानांतरित किया जाए. ब्राउज़र इमेज डेटा भेजता है, सर्वर Tesseract चलाकर परिणाम लौटाता है. सर्वर भाग के लिए प्रचलित विकल्प Flask या FastAPI हैं. इससे भी ऊपर, आप ऐसा फ्रेमवर्क ले सकते हैं जो UI और Python बैकएंड को पहले से जोड़ देता हो. नीचे का उदाहरण NiceGUI का उपयोग करता है और सर्वर पर वही OCR तर्क दिखाता है, साथ ही pandas DataFrame को तालिका के रूप में रेंडर करना भी.
# server_app.py
from nicegui import ui
import os
import cv2
import pytesseract
import pandas as pd
# यदि आपके सिस्टम पर आवश्यकता हो, तो यहाँ Tesseract का पथ उसी तरह सेट करें जैसे लोकली करते हैं
# pytesseract.pytesseract.tesseract_cmd = r"Tesseract-OCR\tesseract.exe"
def parse_image(img_path):
gray = cv2.imread(img_path, 0)
mask = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
text = pytesseract.image_to_string(mask, lang='eng', config='--psm 6')
compact = "\n".join([ln.rstrip() for ln in text.splitlines() if ln.strip()])
return compact.split('\n')
def build_df():
folder = 'SQL_NOTES'
folder = '.' # छवियाँ रखने वाला फ़ोल्डर
collected = []
for name in os.listdir(folder):
if name.startswith("image"):
collected.append(os.path.join(folder, name))
records = [parse_image(p) for p in collected]
return pd.DataFrame(records).T
def on_press(e):
df = build_df()
status_label.set_text(df.to_string())
ui.table.from_pandas(df)
ui.button("Press to run", on_click=on_press)
status_label = ui.label("Waiting for result...")
ui.run()
यदि आप सर्वर फ़ोल्डर स्कैन करने के बजाय उपयोगकर्ताओं को छवियाँ अपलोड करने देना चाहते हैं, तो NiceGUI अपलोड एलिमेंट भी देता है. OCR अब भी सर्वर पर चलता है और परिणाम पेज पर वापस भेजता है.
# server_upload_app.py
from nicegui import ui
import cv2
import pytesseract
import pandas as pd
import numpy as np
def on_upload(e):
payload = e.content.read()
arr = np.frombuffer(payload, np.uint8)
mat = cv2.imdecode(arr, 0)
mask = cv2.threshold(mat, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
text = pytesseract.image_to_string(mask, lang='eng', config='--psm 6')
compact = "\n".join([ln.rstrip() for ln in text.splitlines() if ln.strip()])
rows = [compact.split('\n')]
df = pd.DataFrame(rows).T
outcome.set_text(df.to_string())
ui.table.from_pandas(df)
ui.upload(on_upload=on_upload)
outcome = ui.label("Waiting for result...")
ui.run()
यह भेद क्यों मायने रखता है
ब्राउज़र सैंडबॉक्स को समझना समय बचाता है और नाज़ुक हैक्स से दूर रखता है. PyScript को JavaScript जैसी ही पाबंदियाँ मिलती हैं—यानी मनमानी लोकल फाइल लिस्टिंग नहीं, और वेब पेज से नेटिव बाइनरी को लॉन्च करना भी नहीं. भले ही Chromium-आधारित ब्राउज़र माउंटिंग के जरिए उपयोगकर्ता-स्वीकृत डायरेक्टरी उपलब्ध करा दें, यह लोकल प्रोग्राम चलाने पर लगी रोक को नहीं बदलता. चूँकि OCR Tesseract और नेटिव एक्सटेंशनों पर निर्भर है, वेब अनुभव बनाते समय इसे सर्वर-साइड ही रखना चाहिए.
मुख्य बातें और समापन
OCR रनटाइम को Python बैकएंड पर रखें और ब्राउज़र में केवल हल्का-सा UI उजागर करें. यदि आपके पास पहले से एक काम करता हुआ डेस्कटॉप स्क्रिप्ट है, तो उसके तर्क को Flask या FastAPI जैसे परिचित टूल के जरिए सर्वर एंडपॉइंट में ले जाएँ, या NiceGUI जैसी एकीकृत स्टैक पर भरोसा करें जो pandas DataFrame को सीधे दिखा सकती है. PyScript में pytesseract.pytesseract.tesseract_cmd के काम करने की उम्मीद न करें, और ब्राउज़र में लोकल फ़ोल्डरों के लिए os.listdir पर निर्भर न रहें. संदेह हो तो https://docs.pyscript.net/2025.8.1/user-guide/filesystem/ पर PyScript फाइल सिस्टम गाइड देखें और ब्राउज़र को एक अविश्वसनीय, सैंडबॉक्स्ड क्लाइंट मानें जो आपके सर्वर से डेटा का आदान-प्रदान करता है—जहाँ वास्तविक OCR होता है.
यह लेख StackOverflow पर प्रश्न (लेखक: nasrin begum pathan) और furas के उत्तर पर आधारित है।