feat(chunks): target-based chunking con config centralizzata

Introduce chunks/config.py come unica fonte di verità per tutti i
parametri della pipeline di chunking. TARGET_CHARS + CHUNK_TOLERANCE
sostituiscono MIN_CHARS/MAX_CHARS: il chunker mira a una dimensione
target e si avvicina il più possibile rispettando il vincolo assoluto
di terminare ogni chunk su un confine di frase (punto/punteggiatura).

- config.py: TARGET_CHARS, CHUNK_TOLERANCE, SPLIT_THRESHOLD_FACTOR,
  PROTECT_TABLES, FIX_MAX_ITERATIONS, STRATEGY_OVERRIDES per strategia
- chunker.py: algoritmo target-based (emit quando frase successiva
  sfora upper_body = upper - prefix_len), table protection atomica,
  override MIN/MAX/overlap per ciascuna delle 4 strategie
- verify_chunks.py: soglie derivate da target*(1±tolerance)
- fix_chunks.py: _split_at_boundary sempre su punteggiatura finale,
  loop ricorsivo fix→verify fino a FIX_MAX_ITERATIONS, split solo
  per chunk > upper × SPLIT_THRESHOLD_FACTOR

Risultato su bitcoin: 694 chunk, 0 incompleti, 83% in range [450,750],
tutti terminanti su punteggiatura indipendentemente dalla dimensione.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-11 15:45:24 +02:00
parent d590346539
commit e264bc52b1
4 changed files with 342 additions and 130 deletions
+88
View File
@@ -0,0 +1,88 @@
#!/usr/bin/env python3
"""
Parametri di configurazione della pipeline di chunking.
Modifica questo file per cambiare il comportamento di chunker.py,
verify_chunks.py e fix_chunks.py senza toccare il codice applicativo.
"""
# ─── Grandezza target dei chunk ───────────────────────────────────────────────
#
# TARGET_CHARS è la dimensione ideale a cui il chunker mira.
# CHUNK_TOLERANCE è la tolleranza relativa (es. 0.25 = ±25%).
#
# range accettabile = [TARGET × (1 TOL), TARGET × (1 + TOL)]
#
# Con TARGET=600 e TOL=0.25 → ogni chunk sarà tra 450 e 750 char,
# il più vicino possibile a 600, terminando sempre su un confine di frase.
#
TARGET_CHARS = 600
CHUNK_TOLERANCE = 0.25
# ─── Overlap ──────────────────────────────────────────────────────────────────
# Numero di frasi ripetute all'inizio del chunk successivo per preservare
# il contesto tra chunk adiacenti della stessa sezione.
OVERLAP_SENTENCES = 1
# ─── Soglie di validazione ────────────────────────────────────────────────────
# fix_chunks.py spezza un chunk "too_long" solo se supera upper × questo fattore.
# Es. upper=750, fattore=1.5 → split solo per chunk > 1125 char.
# Chunk in [upper, upper×fattore] restano come warning non bloccanti.
SPLIT_THRESHOLD_FACTOR = 1.5
MATH_SYMS_MIN = 3 # min. simboli math per declassare incomplete → incomplete_math
# ─── Pattern e formato ────────────────────────────────────────────────────────
SENTENCE_SPLIT_PATTERN = r"(?<=[.!?»])\s+"
PREFIX_TEMPLATE = "[{sezione} > {titolo}]"
# ─── Protezione contenuti speciali ────────────────────────────────────────────
# Se True, un blocco prevalentemente tabella Markdown (≥50% righe |…|)
# viene emesso come chunk atomico senza sentence-splitting.
PROTECT_TABLES = True
# Riservato — blocchi LaTeX non spezzabili (implementazione futura).
PROTECT_MATH = True
# ─── Fix behavior ─────────────────────────────────────────────────────────────
# Numero massimo di iterazioni del loop fix → verify → fix.
# Con 1 si ottiene il comportamento originale (fix singolo senza re-verifica).
FIX_MAX_ITERATIONS = 3
# ─── Override per strategia ───────────────────────────────────────────────────
#
# Sovrascrivono TARGET_CHARS / CHUNK_TOLERANCE / OVERLAP_SENTENCES
# per la specifica strategia indicata in structure_profile.json.
# Chiavi riconosciute: "target_chars", "tolerance", "overlap".
#
STRATEGY_OVERRIDES: dict[str, dict] = {
"h3_aware": {
# Documenti strutturati H2→H3: chunk medi, overlap moderato.
"target_chars": 600,
"tolerance": 0.25,
"overlap": 2,
},
"h2_paragraph_split": {
# Documenti piatti (solo H2): chunk più ampi, overlap ridotto.
"target_chars": 800,
"tolerance": 0.25,
"overlap": 1,
},
"paragraph": {
# Documenti senza header significativi: chunk più corti.
"target_chars": 500,
"tolerance": 0.30,
"overlap": 1,
},
"sliding_window": {
# Testo lineare/narrativo: finestre ampie, overlap generoso.
"target_chars": 800,
"tolerance": 0.25,
"overlap": 3,
},
}