""" Moteur OCR Surya — extraction texte ligne par ligne. Usage CPU uniquement. """ import os os.environ.setdefault("SURYA_TORCH_DEVICE", "cpu") os.environ.setdefault("TORCH_DEVICE", "cpu") import logging import time from PIL import Image logger = logging.getLogger(__name__) LANGS = ["fr", "en", "ar"] _surya_det = None _surya_rec = None def get_surya_models(): global _surya_det, _surya_rec if _surya_det is None or _surya_rec is None: logger.info("Chargement modèles Surya (CPU)…") t0 = time.time() from surya.models import DetectionPredictor from surya.recognition import RecognitionPredictor _surya_det = DetectionPredictor(device="cpu") _surya_rec = RecognitionPredictor(device="cpu") logger.info("Surya prêt en %.1fs", time.time() - t0) return _surya_det, _surya_rec def run_surya_ocr(pil_image: Image.Image) -> dict: det, rec = get_surya_models() img = pil_image.convert("RGB") page_w, page_h = img.size t0 = time.time() rec_preds = rec([img], [LANGS], det_predictor=det) elapsed = time.time() - t0 words = [] for line in rec_preds[0].text_lines: text = line.text.strip() if not text: continue if hasattr(line, "bbox") and line.bbox: x1, y1, x2, y2 = line.bbox else: x1, y1, x2, y2 = 0, 0, page_w, page_h box = [ int(x1 / page_w * 1000), int(y1 / page_h * 1000), int(x2 / page_w * 1000), int(y2 / page_h * 1000), ] words.append({ "text": text, "box": box, "confidence": round(line.confidence, 3), "is_arabic": False, }) return { "words": words, "page_w": page_w, "page_h": page_h, "full_text": "\n".join(w["text"] for w in words), "n_lines": len(words), "ocr_time": round(elapsed, 2), }