69 lines
3.0 KiB
Python
69 lines
3.0 KiB
Python
"""
|
|
FILE: app/core/chunking/chunking_propagation.py
|
|
DESCRIPTION: Injiziert Sektions-Kanten physisch in den Text (Embedding-Enrichment).
|
|
Fix v3.3.6: Nutzt robustes Parsing zur Erkennung vorhandener Kanten,
|
|
um Dopplungen direkt hinter [!edge] Callouts format-agnostisch zu verhindern.
|
|
"""
|
|
from typing import List, Dict, Set
|
|
from .chunking_models import Chunk
|
|
from .chunking_parser import parse_edges_robust
|
|
|
|
def propagate_section_edges(chunks: List[Chunk]) -> List[Chunk]:
|
|
"""
|
|
Sammelt Kanten pro Sektion und schreibt sie hart in den Text und das Window.
|
|
Verhindert Dopplungen, wenn Kanten bereits via [!edge] Callout vorhanden sind.
|
|
"""
|
|
# 1. Sammeln: Alle expliziten Kanten pro Sektions-Pfad aggregieren
|
|
section_map: Dict[str, Set[str]] = {} # path -> set(kind:target)
|
|
|
|
for ch in chunks:
|
|
# Root-Level "/" ignorieren (zu global), Fokus auf spezifische Kapitel
|
|
if not ch.section_path or ch.section_path == "/":
|
|
continue
|
|
|
|
# Nutzt den robusten Parser aus dem Package
|
|
# WP-24c v4.2.7: parse_edges_robust gibt jetzt Liste von Dicts zurück
|
|
edge_infos = parse_edges_robust(ch.text)
|
|
if edge_infos:
|
|
if ch.section_path not in section_map:
|
|
section_map[ch.section_path] = set()
|
|
for edge_info in edge_infos:
|
|
section_map[ch.section_path].add(edge_info["edge"])
|
|
|
|
# 2. Injizieren: Kanten in jeden Chunk der Sektion zurückschreiben (Broadcasting)
|
|
for ch in chunks:
|
|
if ch.section_path in section_map:
|
|
edges_to_add = section_map[ch.section_path]
|
|
if not edges_to_add:
|
|
continue
|
|
|
|
# Vorhandene Kanten (Typ:Ziel) in DIESEM Chunk ermitteln,
|
|
# um Dopplungen (z.B. durch Callouts) zu vermeiden.
|
|
# WP-24c v4.2.7: parse_edges_robust gibt jetzt Liste von Dicts zurück
|
|
existing_edge_infos = parse_edges_robust(ch.text)
|
|
existing_edges = {ei["edge"] for ei in existing_edge_infos}
|
|
|
|
injections = []
|
|
# Sortierung für deterministische Ergebnisse
|
|
for e_str in sorted(list(edges_to_add)):
|
|
# Wenn die Kante (Typ + Ziel) bereits vorhanden ist (egal welches Format),
|
|
# überspringen wir die Injektion für diesen Chunk.
|
|
if e_str in existing_edges:
|
|
continue
|
|
|
|
kind, target = e_str.split(':', 1)
|
|
injections.append(f"[[rel:{kind}|{target}]]")
|
|
|
|
if injections:
|
|
# Physische Anreicherung
|
|
# Triple-Newline für saubere Trennung im Embedding-Fenster
|
|
block = "\n\n\n" + " ".join(injections)
|
|
ch.text += block
|
|
|
|
# Auch ins Window schreiben, da Qdrant hier sucht!
|
|
if ch.window:
|
|
ch.window += block
|
|
else:
|
|
ch.window = ch.text
|
|
|
|
return chunks |