--- a/immich_ml/models/ocr/postprocess.py	2026-09-13 13:27:21.777450388 +0300
+++ b/immich_ml/models/ocr/postprocess.py	2026-09-13 13:27:59.085108431 +0300
@@ -21,7 +21,7 @@
     return np.concatenate([top, bottom[..., ::-1, :]], axis=-2)


-def _span(values: cv2.typing.MatLike, limit: int) -> tuple[int, int]:
+def _span(values, limit: int) -> tuple[int, int]:
     lo, hi = math.floor(values.min()), math.ceil(values.max())
     return min(max(lo, 0), limit - 1), min(max(hi, 0), limit - 1)

@@ -88,7 +88,7 @@
         return scaled, np.array(scores, dtype=np.float32)

     @staticmethod
-    def box_score(probs: NDArray[np.float32], poly: cv2.typing.MatLike) -> float:
+    def box_score(probs: NDArray[np.float32], poly) -> float:
         """Mean probability inside `poly`: the min-area rect for "fast", the contour for "slow"."""
         h, w = probs.shape[:2]
         xs, ys = poly.reshape(-1, 2).T
@@ -100,7 +100,7 @@
         cv2.fillPoly(mask, points, 1, offset=(-xmin, -ymin))  # type: ignore[call-overload]
         return cv2.mean(probs[ymin : ymax + 1, xmin : xmax + 1], mask)[0]

-    def unclip(self, rect: cv2.typing.RotatedRect) -> tuple[NDArray[np.float32], float]:
+    def unclip(self, rect) -> tuple[NDArray[np.float32], float]:
         width, height = rect[1]
         grow = width * height * self.unclip_ratio / (width + height)
         points = cv2.boxPoints((rect[0], (width + grow, height + grow), rect[2])).astype(np.float32, copy=False)
