| | """ |
| | OCR Engine Factory |
| | |
| | Provides convenient functions to create and manage OCR engines. |
| | Handles fallback logic and singleton management. |
| | """ |
| |
|
| | from typing import Optional, Dict |
| | from loguru import logger |
| |
|
| | from .base import OCREngine, OCRConfig |
| | from .paddle_ocr import PaddleOCREngine, HAS_PADDLEOCR |
| | from .tesseract_ocr import TesseractOCREngine, HAS_TESSERACT |
| |
|
| |
|
| | |
| | _ocr_engines: Dict[str, OCREngine] = {} |
| |
|
| |
|
| | def create_ocr_engine( |
| | engine_type: str = "auto", |
| | config: Optional[OCRConfig] = None, |
| | initialize: bool = True, |
| | ) -> OCREngine: |
| | """ |
| | Create an OCR engine instance. |
| | |
| | Args: |
| | engine_type: Engine type: "paddle", "paddleocr", "tesseract", or "auto" |
| | config: OCR configuration |
| | initialize: Whether to initialize the engine immediately |
| | |
| | Returns: |
| | OCREngine instance |
| | |
| | Raises: |
| | RuntimeError: If no OCR engine is available |
| | """ |
| | if config is None: |
| | config = OCRConfig() |
| |
|
| | |
| | if engine_type == "paddleocr": |
| | engine_type = "paddle" |
| |
|
| | |
| | if engine_type == "auto": |
| | if HAS_PADDLEOCR: |
| | engine_type = "paddle" |
| | logger.info("Auto-selected PaddleOCR engine") |
| | elif HAS_TESSERACT: |
| | engine_type = "tesseract" |
| | logger.info("Auto-selected Tesseract engine") |
| | else: |
| | raise RuntimeError( |
| | "No OCR engine available. Install one of: " |
| | "pip install paddleocr paddlepaddle-gpu OR " |
| | "pip install pytesseract (+ apt-get install tesseract-ocr)" |
| | ) |
| |
|
| | |
| | if engine_type == "paddle": |
| | if not HAS_PADDLEOCR: |
| | raise RuntimeError( |
| | "PaddleOCR not installed. Install with: " |
| | "pip install paddleocr paddlepaddle-gpu" |
| | ) |
| | engine = PaddleOCREngine(config) |
| |
|
| | elif engine_type == "tesseract": |
| | if not HAS_TESSERACT: |
| | raise RuntimeError( |
| | "Tesseract not installed. Install with: " |
| | "pip install pytesseract (+ apt-get install tesseract-ocr)" |
| | ) |
| | engine = TesseractOCREngine(config) |
| |
|
| | else: |
| | raise ValueError(f"Unknown engine type: {engine_type}") |
| |
|
| | |
| | if initialize: |
| | engine.initialize() |
| |
|
| | return engine |
| |
|
| |
|
| | def get_ocr_engine( |
| | engine_type: str = "auto", |
| | config: Optional[OCRConfig] = None, |
| | ) -> OCREngine: |
| | """ |
| | Get or create an OCR engine singleton. |
| | |
| | Reuses existing engine instances for efficiency. |
| | |
| | Args: |
| | engine_type: Engine type: "paddle", "paddleocr", "tesseract", or "auto" |
| | config: OCR configuration (only used for new instances) |
| | |
| | Returns: |
| | OCREngine instance |
| | """ |
| | global _ocr_engines |
| |
|
| | |
| | if engine_type == "paddleocr": |
| | engine_type = "paddle" |
| |
|
| | |
| | if engine_type == "auto": |
| | if HAS_PADDLEOCR: |
| | engine_type = "paddle" |
| | elif HAS_TESSERACT: |
| | engine_type = "tesseract" |
| | else: |
| | raise RuntimeError("No OCR engine available") |
| |
|
| | |
| | if engine_type in _ocr_engines: |
| | return _ocr_engines[engine_type] |
| |
|
| | |
| | engine = create_ocr_engine(engine_type, config, initialize=True) |
| | _ocr_engines[engine_type] = engine |
| |
|
| | return engine |
| |
|
| |
|
| | def get_available_engines() -> Dict[str, bool]: |
| | """ |
| | Get availability status of OCR engines. |
| | |
| | Returns: |
| | Dict mapping engine name to availability |
| | """ |
| | return { |
| | "paddle": HAS_PADDLEOCR, |
| | "tesseract": HAS_TESSERACT, |
| | } |
| |
|
| |
|
| | def clear_engines(): |
| | """Clear all cached OCR engine instances.""" |
| | global _ocr_engines |
| | _ocr_engines.clear() |
| | logger.debug("Cleared OCR engine cache") |
| |
|
| |
|
| | class OCREngineManager: |
| | """ |
| | Context manager for OCR engine lifecycle. |
| | |
| | Example: |
| | with OCREngineManager("paddle") as engine: |
| | result = engine.recognize(image) |
| | """ |
| |
|
| | def __init__( |
| | self, |
| | engine_type: str = "auto", |
| | config: Optional[OCRConfig] = None, |
| | use_singleton: bool = True, |
| | ): |
| | """ |
| | Initialize OCR engine manager. |
| | |
| | Args: |
| | engine_type: Engine type |
| | config: OCR configuration |
| | use_singleton: Whether to use singleton instance |
| | """ |
| | self.engine_type = engine_type |
| | self.config = config |
| | self.use_singleton = use_singleton |
| | self._engine: Optional[OCREngine] = None |
| | self._owned = False |
| |
|
| | def __enter__(self) -> OCREngine: |
| | """Enter context and return engine.""" |
| | if self.use_singleton: |
| | self._engine = get_ocr_engine(self.engine_type, self.config) |
| | self._owned = False |
| | else: |
| | self._engine = create_ocr_engine(self.engine_type, self.config) |
| | self._owned = True |
| |
|
| | return self._engine |
| |
|
| | def __exit__(self, exc_type, exc_val, exc_tb): |
| | """Exit context.""" |
| | |
| | if self._owned and self._engine: |
| | |
| | pass |
| | self._engine = None |
| | return False |
| |
|