fix(ocr): address review feedback — selective retry, remove unused confidence(), deduplicate import

- Only retry transient errors (timeout/connection/5xx) in LLM vision OCR;
  deterministic 4xx failures now raise immediately without delay
- Remove unused confidence() method that hid a redundant OCR call
- Remove duplicate model_validator import in env_schema.py

Signed-off-by: shadowinlife <shadowinlife@gmail.com>

AI-Contributed/Feature: 0/46
AI-Contributed/UT: 0/0
This commit is contained in:
shadowinlife committed 2026-07-16 16:26:47 +08:00
1 parent 606f20d3c2
commit 021bcd502d
3 files changed
+31 -15

No files matched your search

-1
View File
@@ -21,7 +21,6 @@ from __future__ import annotations
import os
from pydantic import model_validator
from typing import Annotated, Any
from pydantic import BaseModel, BeforeValidator, ConfigDict, Field, model_validator
+31 -3
View File
@@ -206,7 +206,11 @@ class LlmVisionOcrEngine:
b64 = self._numpy_to_base64(image)
# 1 retry for transient network errors
# 1 retry for transient network errors only.
# Deterministic failures (4xx client errors like 401/403/404/422)
# are raised immediately to avoid 90s x 2 pointless delay.
from openai import APIConnectionError, APITimeoutError, APIStatusError
for attempt in range(2):
try:
response = client.chat.completions.create(
@@ -237,9 +241,10 @@ class LlmVisionOcrEngine:
)
text = response.choices[0].message.content or ""
return text.strip()
except Exception as exc:
except (APITimeoutError, APIConnectionError) as exc:
# Transient network errors — retry once.
if attempt == 0:
logger.warning("OCR attempt 1 failed, retrying: %s", exc)
logger.warning("OCR attempt 1 failed (transient), retrying: %s", exc)
continue
logger.error(
"LLM vision OCR failed (%s / %s): %s",
@@ -248,6 +253,29 @@ class LlmVisionOcrEngine:
exc,
)
return ""
except APIStatusError as exc:
# 5xx server errors are transient — retry once.
if exc.status_code >= 500 and attempt == 0:
logger.warning("OCR attempt 1 failed (server %d), retrying: %s", exc.status_code, exc)
continue
# 4xx client errors (401, 403, 404, 422, etc.) are deterministic — raise immediately.
logger.error(
"LLM vision OCR failed (%s / %s): HTTP %d — %s",
config["provider"],
config["model"],
exc.status_code,
exc,
)
raise
except Exception as exc:
# Unexpected errors — do not retry.
logger.error(
"LLM vision OCR failed (%s / %s): %s",
config["provider"],
config["model"],
exc,
)
raise
return ""
def confidence(self, image: np.ndarray) -> float | None:
-11
View File
@@ -35,17 +35,6 @@ class RapidOcrEngine:
return ""
return "\n".join(item[1] for item in result)
def confidence(self, image: np.ndarray) -> float | None:
"""Return mean OCR confidence (0-1), or None if unavailable."""
if not self.is_available():
return None
result, _ = self._engine(image)
if not result:
return None
# RapidOCR returns (bbox, text, confidence) tuples
confidences = [item[2] for item in result if len(item) > 2]
return sum(confidences) / len(confidences) if confidences else None
# Self-register to built-in engine table
from src.tools.ocr.engine import register_builtin # noqa: E402