feat: OCR docTR par page — plus de seuil global, traite chaque page pauvre individuellement
L'OCR docTR est maintenant déclenché page par page (< 150 chars) au lieu d'un seuil global sur tout le document. Permet de traiter les documents mixtes (pages texte + pages scannées) sans pénaliser le temps de traitement sur les pages déjà riches en texte. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1192,16 +1192,23 @@ def extract_text_with_fallback_ocr(pdf_path: Path) -> Tuple[List[str], List[List
|
|||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# --- Passe 3 : OCR docTR si PDF scanné (très peu de texte) ---
|
# --- Passe 3 : OCR docTR sur les pages pauvres en texte ---
|
||||||
|
# Pas de seuil global : on OCR uniquement les pages individuelles
|
||||||
|
# qui ont peu de texte (< 150 chars), puis on garde le meilleur résultat
|
||||||
|
# par page. Les pages déjà riches en texte ne sont pas touchées.
|
||||||
|
_OCR_PAGE_THRESHOLD = 150 # chars minimum pour considérer une page comme "texte OK"
|
||||||
total_chars = sum(len(x or "") for x in pages_text)
|
total_chars = sum(len(x or "") for x in pages_text)
|
||||||
ocr_word_map: OcrWordMap = {}
|
ocr_word_map: OcrWordMap = {}
|
||||||
if total_chars < 200 and _DOCTR_AVAILABLE and fitz is not None:
|
sparse_pages = [i for i, p in enumerate(pages_text) if len(p or "") < _OCR_PAGE_THRESHOLD]
|
||||||
|
if sparse_pages and _DOCTR_AVAILABLE and fitz is not None:
|
||||||
try:
|
try:
|
||||||
model = _get_doctr_model()
|
model = _get_doctr_model()
|
||||||
doc = fitz.open(str(pdf_path))
|
doc = fitz.open(str(pdf_path))
|
||||||
ocr_pages: List[str] = []
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
for i in range(len(doc)):
|
ocr_replaced = 0
|
||||||
|
for i in sparse_pages:
|
||||||
|
if i >= len(doc):
|
||||||
|
continue
|
||||||
pix = doc[i].get_pixmap(dpi=300)
|
pix = doc[i].get_pixmap(dpi=300)
|
||||||
img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
|
img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
|
||||||
result = model([np.array(img)])
|
result = model([np.array(img)])
|
||||||
@@ -1213,15 +1220,17 @@ def extract_text_with_fallback_ocr(pdf_path: Path) -> Tuple[List[str], List[List
|
|||||||
(x0, y0), (x1, y1) = w.geometry
|
(x0, y0), (x1, y1) = w.geometry
|
||||||
page_words.append((w.value, x0, y0, x1, y1))
|
page_words.append((w.value, x0, y0, x1, y1))
|
||||||
page_text += " ".join(w.value for w in line.words) + "\n"
|
page_text += " ".join(w.value for w in line.words) + "\n"
|
||||||
|
# Remplacer seulement si l'OCR produit plus de texte
|
||||||
|
if len(page_text) > len(pages_text[i] or ""):
|
||||||
|
pages_text[i] = page_text
|
||||||
ocr_word_map[i] = page_words
|
ocr_word_map[i] = page_words
|
||||||
ocr_pages.append(page_text)
|
ocr_replaced += 1
|
||||||
doc.close()
|
doc.close()
|
||||||
if sum(len(p) for p in ocr_pages) > total_chars:
|
if ocr_replaced > 0:
|
||||||
pages_text = ocr_pages
|
|
||||||
ocr_used = True
|
ocr_used = True
|
||||||
else:
|
log.info("OCR docTR : %d/%d pages remplacées", ocr_replaced, len(sparse_pages))
|
||||||
ocr_word_map = {}
|
except Exception as e:
|
||||||
except Exception:
|
log.warning("OCR docTR échoué : %s", e)
|
||||||
ocr_word_map = {}
|
ocr_word_map = {}
|
||||||
return pages_text, tables_lines, ocr_used, ocr_word_map
|
return pages_text, tables_lines, ocr_used, ocr_word_map
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user