e1b5298b20
Porta da branch marker la riscrittura completa di conversione/_pipeline/ (9 stadi PyMuPDF) e la suite tests/ senza modificare il resto del progetto RAG (ollama/, step-5/, step-6/, step-8/, rag.py, retrieve.py, config.py). requirements.txt: aggiunge PyMuPDF>=1.24.0 e pytest>=8.0, mantiene chromadb, rimuove opendataloader-pdf e pymupdf4llm. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
83 lines
3.0 KiB
Python
83 lines
3.0 KiB
Python
"""Validazione PDF e estrazione metadati tramite fitz."""
|
|
import re
|
|
from pathlib import Path
|
|
|
|
|
|
def validate_pdf(pdf_path: Path) -> tuple[bool, str]:
|
|
"""Verifica esistenza, leggibilità e presenza di testo digitale estraibile."""
|
|
if not pdf_path.exists():
|
|
return False, f"File non trovato: {pdf_path}"
|
|
if pdf_path.suffix.lower() != ".pdf":
|
|
return False, f"Non è un PDF: {pdf_path.name}"
|
|
size = pdf_path.stat().st_size
|
|
if size == 0:
|
|
return False, "File vuoto"
|
|
if size < 1024:
|
|
return False, f"File troppo piccolo ({size} byte) — probabilmente corrotto"
|
|
|
|
try:
|
|
import pdfplumber
|
|
with pdfplumber.open(pdf_path) as pdf:
|
|
n_pages = len(pdf.pages)
|
|
if n_pages == 0:
|
|
return False, "PDF senza pagine"
|
|
sample = min(5, n_pages)
|
|
pages_with_text = sum(
|
|
1 for i in range(sample)
|
|
if len((pdf.pages[i].extract_text() or "").strip()) > 50
|
|
)
|
|
if pages_with_text == 0:
|
|
extended = min(15, n_pages)
|
|
if extended > sample:
|
|
ext_with_text = sum(
|
|
1 for i in range(sample, extended)
|
|
if len((pdf.pages[i].extract_text() or "").strip()) > 50
|
|
)
|
|
if ext_with_text > 0:
|
|
return True, (
|
|
f"{n_pages} pagine — prime {sample} vuote, "
|
|
f"testo trovato in pagine successive "
|
|
f"(possibile copertina immagine)"
|
|
)
|
|
return False, (
|
|
f"Nessun testo nelle prime {extended} pagine "
|
|
f"— probabilmente scansionato (OCR non supportato)"
|
|
)
|
|
return True, f"{n_pages} pagine, testo digitale confermato"
|
|
except MemoryError:
|
|
return False, "Memoria esaurita durante l'apertura del PDF"
|
|
except Exception as e:
|
|
msg = str(e).lower()
|
|
if "password" in msg or "encrypted" in msg:
|
|
return False, "PDF protetto da password"
|
|
return False, f"Impossibile aprire: {e}"
|
|
|
|
|
|
def extract_metadata(pdf_path: Path) -> dict:
|
|
"""
|
|
Estrae title, author, year e page count dal PDF tramite fitz.
|
|
Restituisce un dict con chiavi sempre presenti (stringa vuota se assenti).
|
|
"""
|
|
try:
|
|
import fitz
|
|
doc = fitz.open(str(pdf_path))
|
|
meta = doc.metadata
|
|
pages = len(doc)
|
|
doc.close()
|
|
|
|
year = ""
|
|
creation = meta.get("creationDate", "")
|
|
m = re.match(r"D:(\d{4})", creation)
|
|
if m:
|
|
year = m.group(1)
|
|
|
|
return {
|
|
"source": pdf_path.name,
|
|
"title": (meta.get("title") or "").strip(),
|
|
"author": (meta.get("author") or "").strip(),
|
|
"year": year,
|
|
"pages": pages,
|
|
}
|
|
except Exception:
|
|
return {"source": pdf_path.name, "title": "", "author": "", "year": "", "pages": 0}
|