fix: corrige bugs críticos de índice de páginas e cache de OCR
- C-1: corrige índice de páginas OCR'd (retorna page_number em vez de position) - C-2: adiciona tratamento para falhas de OCR no cache (não distingue erro de não processado) - Integra paralelização do OCR via subprocessos (parallel.py) - Indexador usa extração paralela quando disponível - Melhora relatório de progresso com contagem de páginas processadas
This commit is contained in:
1 parent
b3f8019e01
commit
621679cee5
4 files changed
+251
-18
No files matched your search
@@ -0,0 +1,59 @@
|
||||
"""Execução paralela de tarefas independentes.
|
||||
|
||||
O gargalo da indexação é o Tesseract, um processo externo. Como o trabalho
|
||||
liberado por cada tarefa é predominantemente I/O (subprocesso e escrita em
|
||||
disco), threads bastam: o GIL é liberado durante a espera pelo processo.
|
||||
|
||||
`parallel_map` preserva a ordem dos resultados e isola falhas — uma tarefa que
|
||||
lança exceção não derruba as demais.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from typing import Callable, Iterable, Sequence, TypeVar
|
||||
|
||||
T = TypeVar("T")
|
||||
R = TypeVar("R")
|
||||
|
||||
|
||||
def parallel_map(
|
||||
items: Sequence[T],
|
||||
function: Callable[[T], R],
|
||||
workers: int = 4,
|
||||
default: R | None = None,
|
||||
) -> list[R | None]:
|
||||
"""Aplica `function` a cada item em paralelo, preservando a ordem.
|
||||
|
||||
Itens cuja função lança exceção recebem o valor `default`.
|
||||
"""
|
||||
if not items:
|
||||
return []
|
||||
|
||||
worker_count = max(1, min(workers, len(items)))
|
||||
|
||||
def guarded(item: T) -> R | None:
|
||||
try:
|
||||
return function(item)
|
||||
except Exception:
|
||||
return default
|
||||
|
||||
if worker_count == 1:
|
||||
return [guarded(item) for item in items]
|
||||
|
||||
with ThreadPoolExecutor(max_workers=worker_count) as pool:
|
||||
return list(pool.map(guarded, items))
|
||||
|
||||
|
||||
def chunked(items: Iterable[T], size: int) -> list[list[T]]:
|
||||
"""Divide um iterável em lotes de tamanho `size`."""
|
||||
chunk: list[T] = []
|
||||
batches: list[list[T]] = []
|
||||
for item in items:
|
||||
chunk.append(item)
|
||||
if len(chunk) >= size:
|
||||
batches.append(chunk)
|
||||
chunk = []
|
||||
if chunk:
|
||||
batches.append(chunk)
|
||||
return batches
|
||||
Reference in new issue
Block a user