""" Hugging Face Inference Endpoint — dots.ocr CPU handler. Bu dosyayi Hub repo kokune yukle (handler.py). HF modeli /repository altina mount eder; GPU aramaz. """ from __future__ import annotations import base64 import io import os from typing import Any os.environ.setdefault("LOCAL_RANK", "0") os.environ.setdefault("CUDA_VISIBLE_DEVICES", "") import torch from PIL import Image from qwen_vl_utils import process_vision_info from transformers import AutoModelForCausalLM, AutoProcessor PROMPT_OCR = "Extract the text content from this image." class EndpointHandler: def __init__(self, path: str = "") -> None: model_path = path or os.environ.get("MODEL_DIR") or "/repository" self.processor = AutoProcessor.from_pretrained(model_path, trust_remote_code=True) try: self.model = AutoModelForCausalLM.from_pretrained( model_path, trust_remote_code=True, torch_dtype=torch.float32, device_map="cpu", low_cpu_mem_usage=True, attn_implementation="sdpa", ) except Exception: self.model = AutoModelForCausalLM.from_pretrained( model_path, trust_remote_code=True, torch_dtype=torch.float32, device_map="cpu", low_cpu_mem_usage=True, attn_implementation="eager", ) self.model.eval() def _load_image(self, raw: Any) -> Image.Image: if isinstance(raw, Image.Image): img = raw elif isinstance(raw, str): data = raw.split(",", 1)[1] if raw.startswith("data:") else raw img = Image.open(io.BytesIO(base64.b64decode(data))) elif isinstance(raw, (bytes, bytearray)): img = Image.open(io.BytesIO(raw)) else: raise ValueError("inputs: base64 string veya data:image/... beklenir") img = img.convert("RGB") w, h = img.size m = max(w, h) if m > 1024: s = 1024 / float(m) img = img.resize((max(32, int(w * s)), max(32, int(h * s))), Image.Resampling.LANCZOS) return img def __call__(self, data: dict[str, Any]) -> dict[str, Any]: inputs = data.get("inputs", data) params = data.get("parameters") or {} if isinstance(inputs, dict): raw = inputs.get("image") or inputs.get("image_url") or inputs.get("data") prompt = inputs.get("prompt") or params.get("prompt") or PROMPT_OCR else: raw = inputs prompt = params.get("prompt") or PROMPT_OCR image = self._load_image(raw) messages = [ { "role": "user", "content": [ {"type": "image", "image": image}, {"type": "text", "text": str(prompt)}, ], } ] text = self.processor.apply_chat_template( messages, tokenize=False, add_generation_prompt=True ) image_inputs, video_inputs = process_vision_info(messages) kwargs = { "text": [text], "images": image_inputs, "padding": True, "return_tensors": "pt", } if video_inputs: kwargs["videos"] = video_inputs batch = self.processor(**kwargs) max_new = int(params.get("max_new_tokens") or 2048) with torch.inference_mode(): out_ids = self.model.generate(**batch, max_new_tokens=max_new) trimmed = [o[len(i) :] for i, o in zip(batch.input_ids, out_ids)] text_out = self.processor.batch_decode( trimmed, skip_special_tokens=True, clean_up_tokenization_spaces=False )[0] return {"generated_text": text_out, "device": "cpu"}