feat(format): B3.5 — PDF smart-fit rewrite + critical fontname=None fix
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 2m44s
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 2m44s
ROOT CAUSE FIX: PyMuPDF silently raised AttributeError when fontname=None was passed to insert_textbox. The try/except in _try_insert was swallowing the error and returning None, causing every block to be skipped via the graceful failure path. Setting fontname='helv' as the default unblocks the entire PDF translation pipeline. SMART-FIT: rewrite _write_translated_block with proper tier-fallback: - Tier 0: original bbox at original size - Tier 1: expanded horizontal - Tier 2: expanded vertical (3x original height) - Tier 3: shrink once (0.93x) - Tier 4: shrink twice (0.87x cumulative) - Tier 5: min size floor (90% for headings, 75% for body) - Tier 6: graceful skip with visible placeholder REDACTION: single redaction per block (was per sub-bbox, creating 100+ redaction rectangles per page). Now only 1 redaction per text block. FEATURE FLAG: PDF_SMART_FIT_ENABLED (default true, observation-first). METRICS: text_overflow -> format_elements_lost_total. RESULT ON REAL PDF: Before: fonts shrunk 22pt->5.6pt, hierarchy destroyed After: fonts EXACT match: [8, 11, 12, 14, 16, 22] preserved
This commit is contained in:
55
scripts/debug_smart_fit_trace.py
Normal file
55
scripts/debug_smart_fit_trace.py
Normal file
@@ -0,0 +1,55 @@
|
||||
"""Debug trace the smart-fit behavior on a real PDF."""
|
||||
import sys
|
||||
sys.path.insert(0, '.')
|
||||
import importlib.util
|
||||
import fitz
|
||||
from pathlib import Path
|
||||
|
||||
spec = importlib.util.spec_from_file_location('pdf_mod', 'translators/pdf_translator.py')
|
||||
pdf_mod = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(pdf_mod)
|
||||
|
||||
original_write = pdf_mod.PDFTranslator._write_translated_block
|
||||
|
||||
def debug_write(self, page, block, font_path, is_rtl):
|
||||
target_size = block['font_size']
|
||||
original_rect = fitz.Rect(block['bbox'])
|
||||
page_rect = page.rect
|
||||
margin = 18
|
||||
is_heading = target_size >= 14
|
||||
if is_heading:
|
||||
expanded_h = original_rect
|
||||
else:
|
||||
expanded_h = fitz.Rect(
|
||||
max(original_rect.x0, page_rect.x0 + margin),
|
||||
original_rect.y0,
|
||||
page_rect.x1 - margin,
|
||||
original_rect.y1,
|
||||
)
|
||||
next_block_y = page_rect.y1 - margin
|
||||
max_expand_y = min(
|
||||
next_block_y - original_rect.y1,
|
||||
original_rect.height * 3.0,
|
||||
)
|
||||
expanded_v = fitz.Rect(
|
||||
expanded_h.x0,
|
||||
expanded_h.y0,
|
||||
expanded_h.x1,
|
||||
expanded_h.y1 + max_expand_y,
|
||||
)
|
||||
text = block['translated'][:40]
|
||||
is_heading_str = "HEAD" if is_heading else "BODY"
|
||||
print(f" [{is_heading_str}] text={text!r} | orig={original_rect.width:.0f}x{original_rect.height:.0f} | exp_v={expanded_v.width:.0f}x{expanded_v.height:.0f} | size={target_size}", flush=True)
|
||||
result = original_write(self, page, block, font_path, is_rtl)
|
||||
print(f" result: {result}", flush=True)
|
||||
return result
|
||||
|
||||
pdf_mod.PDFTranslator._write_translated_block = debug_write
|
||||
|
||||
PDFTranslator = pdf_mod.PDFTranslator
|
||||
PDFTranslator().translate_file(
|
||||
Path('sample_files/test_corpus/test_pdf.pdf'),
|
||||
Path('sample_files/test_corpus/test_pdf_translated.pdf'),
|
||||
target_language='fr',
|
||||
source_language='en',
|
||||
)
|
||||
Reference in New Issue
Block a user