acsaco's picture
download
raw
2.62 kB
"""
OCR Engine - GPU-optimized manga text recognition.
Uses manga-ocr (Hugging Face) on CUDA for fast inference.
Supports batch processing for multiple regions.
"""
import asyncio
import io
from typing import Optional
import numpy as np
import torch
from PIL import Image
from app.core.config import Settings
class OCREngine:
"""
GPU-accelerated OCR using manga-ocr.
Model persists in GPU memory for zero-copy inference.
"""
def __init__(self, settings: Settings):
self.settings = settings
self.model = None
self.device = settings.CUDA_DEVICE
self.processor = None
async def load(self):
"""Load manga-ocr model into GPU memory."""
try:
from manga_ocr import MangaOcr
self.model = MangaOcr()
print(f"[OCR] Loaded manga-ocr on {self.device}")
except Exception as e:
print(f"[OCR] Failed to load manga-ocr: {e}")
self.model = None
async def recognize(self, image: Image.Image, region: Optional[dict] = None) -> dict:
"""
Recognize text in an image region.
Returns { text, confidence, bbox, orientation }.
"""
if region:
# Crop region from image
x, y, w, h = region["x"], region["y"], region["width"], region["height"]
cropped = image.crop((x, y, x + w, y + h))
else:
cropped = image
if self.model is None:
return {"text": "", "confidence": 0, "bbox": region, "orientation": "horizontal"}
# Run OCR in thread pool (non-blocking)
loop = asyncio.get_event_loop()
text = await loop.run_in_executor(None, lambda: self.model(cropped))
return {
"text": text.strip() if text else "",
"confidence": 0.9, # manga-ocr doesn't provide confidence
"bbox": region,
"orientation": region.get("orientation", "horizontal") if region else "horizontal",
}
async def recognize_batch(self, image: Image.Image, regions: list[dict]) -> list[dict]:
"""
Recognize text in multiple regions (sequential but async).
manga-ocr doesn't support true batching, but we use async for non-blocking.
"""
tasks = [self.recognize(image, region) for region in regions]
return await asyncio.gather(*tasks)
async def unload(self):
"""Release GPU memory."""
if self.model is not None:
del self.model
self.model = None
if torch.cuda.is_available():
torch.cuda.empty_cache()

Xet Storage Details

Size:
2.62 kB
·
Xet hash:
86740fd037ab9e06ca5d0dc994a066744751974fa986e3d3295b27d3846b94d2

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.