Spaces:
Sleeping
Sleeping
Pointf5ive commited on
Commit ·
7ad227d
1
Parent(s): f7a5a9f
Accelerate Tesseract fallback with parallel OCR and timeouts
Browse files- smoke_signal_tab.py +46 -5
smoke_signal_tab.py
CHANGED
|
@@ -22,6 +22,7 @@ Self-improvement loop:
|
|
| 22 |
"""
|
| 23 |
|
| 24 |
import csv
|
|
|
|
| 25 |
import hashlib
|
| 26 |
import json
|
| 27 |
import os
|
|
@@ -729,6 +730,18 @@ try:
|
|
| 729 |
SS_RENDER_DPI_FALLBACK = max(72, int(os.environ.get("SS_RENDER_DPI_FALLBACK", "200")))
|
| 730 |
except Exception:
|
| 731 |
SS_RENDER_DPI_FALLBACK = 200
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 732 |
|
| 733 |
|
| 734 |
def _load_surya_runtime():
|
|
@@ -886,14 +899,17 @@ def _run_tesseract_batch(images):
|
|
| 886 |
except Exception as e:
|
| 887 |
return [{"regions": [], "confidence": 0.0, "method": f"error-no-tesseract ({e})"} for _ in images]
|
| 888 |
|
| 889 |
-
|
| 890 |
-
|
|
|
|
|
|
|
| 891 |
try:
|
| 892 |
data = pytesseract.image_to_data(
|
| 893 |
img,
|
| 894 |
lang="eng",
|
| 895 |
-
config="--oem 1 --psm
|
| 896 |
output_type=pytesseract.Output.DICT,
|
|
|
|
| 897 |
)
|
| 898 |
regions = []
|
| 899 |
conf_weighted = 0.0
|
|
@@ -930,9 +946,28 @@ def _run_tesseract_batch(images):
|
|
| 930 |
word_count += wc
|
| 931 |
|
| 932 |
avg_conf = round(conf_weighted / max(word_count, 1), 4) if regions else 0.0
|
| 933 |
-
|
|
|
|
|
|
|
| 934 |
except Exception as e:
|
| 935 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 936 |
|
| 937 |
return outputs
|
| 938 |
|
|
@@ -976,6 +1011,12 @@ def run_ocr(progress=gr.Progress(track_tqdm=False)) -> tuple:
|
|
| 976 |
log.append(log_line(f"✓ Surya models loaded ({surya['api']})"))
|
| 977 |
else:
|
| 978 |
log.append(log_line(f"⚠ Surya unavailable ({surya_error}) — using Tesseract fallback for this run"))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 979 |
|
| 980 |
total_pages_planned = 0
|
| 981 |
total_ocr_targets_planned = 0
|
|
|
|
| 22 |
"""
|
| 23 |
|
| 24 |
import csv
|
| 25 |
+
import concurrent.futures
|
| 26 |
import hashlib
|
| 27 |
import json
|
| 28 |
import os
|
|
|
|
| 730 |
SS_RENDER_DPI_FALLBACK = max(72, int(os.environ.get("SS_RENDER_DPI_FALLBACK", "200")))
|
| 731 |
except Exception:
|
| 732 |
SS_RENDER_DPI_FALLBACK = 200
|
| 733 |
+
try:
|
| 734 |
+
SS_TESSERACT_WORKERS = max(1, int(os.environ.get("SS_TESSERACT_WORKERS", "2")))
|
| 735 |
+
except Exception:
|
| 736 |
+
SS_TESSERACT_WORKERS = 2
|
| 737 |
+
try:
|
| 738 |
+
SS_TESSERACT_TIMEOUT_SEC = max(1, int(os.environ.get("SS_TESSERACT_TIMEOUT_SEC", "18")))
|
| 739 |
+
except Exception:
|
| 740 |
+
SS_TESSERACT_TIMEOUT_SEC = 18
|
| 741 |
+
try:
|
| 742 |
+
SS_TESSERACT_PSM = max(1, int(os.environ.get("SS_TESSERACT_PSM", "6")))
|
| 743 |
+
except Exception:
|
| 744 |
+
SS_TESSERACT_PSM = 6
|
| 745 |
|
| 746 |
|
| 747 |
def _load_surya_runtime():
|
|
|
|
| 899 |
except Exception as e:
|
| 900 |
return [{"regions": [], "confidence": 0.0, "method": f"error-no-tesseract ({e})"} for _ in images]
|
| 901 |
|
| 902 |
+
# Prefer parallel image-level OCR with single-threaded internal OpenMP for better CPU utilization.
|
| 903 |
+
os.environ.setdefault("OMP_THREAD_LIMIT", "1")
|
| 904 |
+
|
| 905 |
+
def _ocr_single(img):
|
| 906 |
try:
|
| 907 |
data = pytesseract.image_to_data(
|
| 908 |
img,
|
| 909 |
lang="eng",
|
| 910 |
+
config=f"--oem 1 --psm {SS_TESSERACT_PSM}",
|
| 911 |
output_type=pytesseract.Output.DICT,
|
| 912 |
+
timeout=SS_TESSERACT_TIMEOUT_SEC,
|
| 913 |
)
|
| 914 |
regions = []
|
| 915 |
conf_weighted = 0.0
|
|
|
|
| 946 |
word_count += wc
|
| 947 |
|
| 948 |
avg_conf = round(conf_weighted / max(word_count, 1), 4) if regions else 0.0
|
| 949 |
+
return {"regions": regions, "confidence": avg_conf, "method": "tesseract"}
|
| 950 |
+
except RuntimeError as e:
|
| 951 |
+
return {"regions": [], "confidence": 0.0, "method": f"error-tesseract-timeout ({e})"}
|
| 952 |
except Exception as e:
|
| 953 |
+
return {"regions": [], "confidence": 0.0, "method": f"error-tesseract ({e})"}
|
| 954 |
+
|
| 955 |
+
if not images:
|
| 956 |
+
return []
|
| 957 |
+
|
| 958 |
+
max_workers = min(SS_TESSERACT_WORKERS, len(images), max(1, os.cpu_count() or 1))
|
| 959 |
+
if max_workers <= 1:
|
| 960 |
+
return [_ocr_single(img) for img in images]
|
| 961 |
+
|
| 962 |
+
outputs = [None] * len(images)
|
| 963 |
+
with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
|
| 964 |
+
futures = {executor.submit(_ocr_single, img): idx for idx, img in enumerate(images)}
|
| 965 |
+
for future in concurrent.futures.as_completed(futures):
|
| 966 |
+
idx = futures[future]
|
| 967 |
+
try:
|
| 968 |
+
outputs[idx] = future.result()
|
| 969 |
+
except Exception as e:
|
| 970 |
+
outputs[idx] = {"regions": [], "confidence": 0.0, "method": f"error-tesseract-future ({e})"}
|
| 971 |
|
| 972 |
return outputs
|
| 973 |
|
|
|
|
| 1011 |
log.append(log_line(f"✓ Surya models loaded ({surya['api']})"))
|
| 1012 |
else:
|
| 1013 |
log.append(log_line(f"⚠ Surya unavailable ({surya_error}) — using Tesseract fallback for this run"))
|
| 1014 |
+
log.append(
|
| 1015 |
+
log_line(
|
| 1016 |
+
f"ℹ Tesseract fallback config: workers={SS_TESSERACT_WORKERS} timeout={SS_TESSERACT_TIMEOUT_SEC}s "
|
| 1017 |
+
f"psm={SS_TESSERACT_PSM} dpi={SS_RENDER_DPI_FALLBACK}"
|
| 1018 |
+
)
|
| 1019 |
+
)
|
| 1020 |
|
| 1021 |
total_pages_planned = 0
|
| 1022 |
total_ocr_targets_planned = 0
|