Pointf5ive commited on
Commit
be1ecc2
·
1 Parent(s): 6c9e2c1

Fix Smoke Signal Surya OCR for new predictor API

Browse files
smoke_signal/scripts/03_ocr_bakeoff.py CHANGED
@@ -27,6 +27,7 @@ Usage:
27
 
28
  import argparse
29
  import csv
 
30
  import json
31
  import sys
32
  import time
@@ -113,8 +114,34 @@ def _safe_load_surya_component(loader, checkpoint: Optional[str]):
113
  def load_surya_context(checkpoint: Optional[str] = None) -> Optional[dict]:
114
  """
115
  Load Surya OCR models once per run.
 
116
  Returns context dict or None if Surya import/loading fails.
117
  """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
  try:
119
  from surya.ocr import run_ocr
120
  from surya.model.detection.model import load_model as load_det_model
@@ -169,14 +196,23 @@ def _run_surya(image_path: Path, langs: list, surya_ctx: Optional[dict] = None)
169
 
170
  try:
171
  image = Image.open(str(image_path)).convert("RGB")
172
- results = ctx["run"](
173
- [image],
174
- [langs],
175
- ctx["det_model"],
176
- ctx["det_processor"],
177
- ctx["rec_model"],
178
- ctx["rec_processor"],
179
- )
 
 
 
 
 
 
 
 
 
180
 
181
  page_result = results[0]
182
 
@@ -191,10 +227,13 @@ def _run_surya(image_path: Path, langs: list, surya_ctx: Optional[dict] = None)
191
  if text:
192
  full_text.append(text)
193
  confidences.append(conf)
 
 
 
194
  words.append({
195
  "text": text,
196
  "confidence": round(conf, 4),
197
- "bbox": line.bbox if hasattr(line, "bbox") else None,
198
  })
199
 
200
  avg_conf = round(sum(confidences) / len(confidences), 4) if confidences else 0.0
 
27
 
28
  import argparse
29
  import csv
30
+ import hashlib
31
  import json
32
  import sys
33
  import time
 
114
  def load_surya_context(checkpoint: Optional[str] = None) -> Optional[dict]:
115
  """
116
  Load Surya OCR models once per run.
117
+ Tries modern predictor API first, then legacy API.
118
  Returns context dict or None if Surya import/loading fails.
119
  """
120
+ # New API (surya-ocr>=0.17 style)
121
+ try:
122
+ from surya.foundation import FoundationPredictor
123
+ from surya.detection import DetectionPredictor
124
+ from surya.recognition import RecognitionPredictor
125
+ try:
126
+ from surya.common.surya.schema import TaskNames
127
+ task_name = TaskNames.ocr_with_boxes
128
+ except Exception:
129
+ task_name = "ocr_with_boxes"
130
+
131
+ foundation_predictor = _safe_load_surya_component(FoundationPredictor, checkpoint)
132
+ det_predictor = DetectionPredictor()
133
+ rec_predictor = RecognitionPredictor(foundation_predictor)
134
+ return {
135
+ "api": "predictor-v2",
136
+ "task_name": task_name,
137
+ "det_predictor": det_predictor,
138
+ "rec_predictor": rec_predictor,
139
+ "checkpoint": checkpoint,
140
+ }
141
+ except Exception:
142
+ pass
143
+
144
+ # Legacy API (surya-ocr<=0.6 style)
145
  try:
146
  from surya.ocr import run_ocr
147
  from surya.model.detection.model import load_model as load_det_model
 
196
 
197
  try:
198
  image = Image.open(str(image_path)).convert("RGB")
199
+ if ctx.get("api") == "predictor-v2":
200
+ results = ctx["rec_predictor"](
201
+ [image],
202
+ task_names=[ctx["task_name"]],
203
+ det_predictor=ctx["det_predictor"],
204
+ highres_images=[image],
205
+ math_mode=True,
206
+ )
207
+ else:
208
+ results = ctx["run"](
209
+ [image],
210
+ [langs],
211
+ ctx["det_model"],
212
+ ctx["det_processor"],
213
+ ctx["rec_model"],
214
+ ctx["rec_processor"],
215
+ )
216
 
217
  page_result = results[0]
218
 
 
227
  if text:
228
  full_text.append(text)
229
  confidences.append(conf)
230
+ bbox = getattr(line, "bbox", None)
231
+ if bbox is None:
232
+ bbox = getattr(line, "polygon", None)
233
  words.append({
234
  "text": text,
235
  "confidence": round(conf, 4),
236
+ "bbox": bbox,
237
  })
238
 
239
  avg_conf = round(sum(confidences) / len(confidences), 4) if confidences else 0.0
smoke_signal_tab.py CHANGED
@@ -735,23 +735,52 @@ def run_ocr() -> tuple:
735
 
736
  log = []
737
 
738
- # Try to import Surya
739
  surya = None
 
 
740
  try:
741
- from surya.ocr import run_ocr as surya_run
742
- from surya.model.detection.model import load_model as load_det
743
- from surya.model.detection.processor import load_processor as load_det_proc
744
- from surya.model.recognition.model import load_model as load_rec
745
- from surya.model.recognition.processor import load_processor as load_rec_proc
746
- log.append(log_line("Loading Surya models (may take a moment)..."))
 
 
 
 
 
 
747
  surya = {
748
- "run": surya_run,
749
- "det_model": load_det(), "det_proc": load_det_proc(),
750
- "rec_model": load_rec(), "rec_proc": load_rec_proc(),
 
751
  }
752
- log.append(log_line("✓ Surya models loaded"))
753
- except ImportError as e:
754
- log.append(log_line(f"⚠ Surya unavailable ({e}) — falling back to text extraction only"))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
755
 
756
  queue_rows = []
757
 
@@ -806,7 +835,23 @@ def run_ocr() -> tuple:
806
  doc.close()
807
 
808
  img = Image.open(render_path).convert("RGB")
809
- result = surya["run"]([img], [["en"]], surya["det_model"], surya["det_proc"], surya["rec_model"], surya["rec_proc"])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
810
  page_result = result[0]
811
 
812
  regions = []
@@ -814,7 +859,10 @@ def run_ocr() -> tuple:
814
  txt = line.text.strip()
815
  if txt:
816
  c = float(line.confidence) if hasattr(line, "confidence") else 1.0
817
- regions.append({"text": txt, "confidence": round(c,4), "bbox": line.bbox, "word_count": len(txt.split())})
 
 
 
818
 
819
  conf = sum(r["confidence"]*r["word_count"] for r in regions) / max(sum(r["word_count"] for r in regions), 1) if regions else 0.0
820
  conf = round(conf, 4)
 
735
 
736
  log = []
737
 
738
+ # Try to import/load Surya (new predictor API first, then legacy API)
739
  surya = None
740
+ surya_error = None
741
+ log.append(log_line("Loading Surya models (may take a moment)..."))
742
  try:
743
+ from surya.foundation import FoundationPredictor
744
+ from surya.detection import DetectionPredictor
745
+ from surya.recognition import RecognitionPredictor
746
+ try:
747
+ from surya.common.surya.schema import TaskNames
748
+ task_name = TaskNames.ocr_with_boxes
749
+ except Exception:
750
+ task_name = "ocr_with_boxes"
751
+
752
+ foundation_predictor = FoundationPredictor()
753
+ det_predictor = DetectionPredictor()
754
+ rec_predictor = RecognitionPredictor(foundation_predictor)
755
  surya = {
756
+ "api": "predictor-v2",
757
+ "task_name": task_name,
758
+ "det_predictor": det_predictor,
759
+ "rec_predictor": rec_predictor,
760
  }
761
+ except Exception as e:
762
+ surya_error = e
763
+ try:
764
+ from surya.ocr import run_ocr as surya_run
765
+ from surya.model.detection.model import load_model as load_det
766
+ from surya.model.detection.processor import load_processor as load_det_proc
767
+ from surya.model.recognition.model import load_model as load_rec
768
+ from surya.model.recognition.processor import load_processor as load_rec_proc
769
+ surya = {
770
+ "api": "legacy-v1",
771
+ "run": surya_run,
772
+ "det_model": load_det(),
773
+ "det_proc": load_det_proc(),
774
+ "rec_model": load_rec(),
775
+ "rec_proc": load_rec_proc(),
776
+ }
777
+ except Exception as legacy_error:
778
+ surya_error = f"{surya_error}; legacy={legacy_error}"
779
+
780
+ if surya:
781
+ log.append(log_line(f"✓ Surya models loaded ({surya['api']})"))
782
+ else:
783
+ log.append(log_line(f"⚠ Surya unavailable ({surya_error}) — falling back to text extraction only"))
784
 
785
  queue_rows = []
786
 
 
835
  doc.close()
836
 
837
  img = Image.open(render_path).convert("RGB")
838
+ if surya["api"] == "predictor-v2":
839
+ result = surya["rec_predictor"](
840
+ [img],
841
+ task_names=[surya["task_name"]],
842
+ det_predictor=surya["det_predictor"],
843
+ highres_images=[img],
844
+ math_mode=True,
845
+ )
846
+ else:
847
+ result = surya["run"](
848
+ [img],
849
+ [["en"]],
850
+ surya["det_model"],
851
+ surya["det_proc"],
852
+ surya["rec_model"],
853
+ surya["rec_proc"],
854
+ )
855
  page_result = result[0]
856
 
857
  regions = []
 
859
  txt = line.text.strip()
860
  if txt:
861
  c = float(line.confidence) if hasattr(line, "confidence") else 1.0
862
+ bbox = getattr(line, "bbox", None)
863
+ if bbox is None:
864
+ bbox = getattr(line, "polygon", None)
865
+ regions.append({"text": txt, "confidence": round(c,4), "bbox": bbox, "word_count": len(txt.split())})
866
 
867
  conf = sum(r["confidence"]*r["word_count"] for r in regions) / max(sum(r["word_count"] for r in regions), 1) if regions else 0.0
868
  conf = round(conf, 4)