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:
1 parent
606f20d3c2
commit
021bcd502d
3 files changed
+31
-15
No files matched your search
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user