mindnet/app/core/chunking/chunking_propagation.py

60 lines
2.4 KiB
Python

"""
FILE: app/core/chunking/chunking_propagation.py
DESCRIPTION: Injiziert Sektions-Kanten physisch in den Text (Embedding-Enrichment).
Fix v3.3.5: Erkennt Wikilink-Targets, um Dopplungen 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
edges = parse_edges_robust(ch.text)
if edges:
if ch.section_path not in section_map:
section_map[ch.section_path] = set()
section_map[ch.section_path].update(edges)
# 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
injections = []
for e_str in edges_to_add:
kind, target = e_str.split(':', 1)
# DER FIX: Wir prüfen, ob das Ziel (target) bereits im Text vorkommt.
# Wir suchen nach [[target]] (Callout-Stil) oder |target]] (Rel-Stil).
if f"[[{target}]]" in ch.text or f"|{target}]]" in ch.text:
continue
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