neues testscript für smart chunker

This commit is contained in:
Lars 2025-12-12 08:59:08 +01:00
parent 2bcf1930fe
commit e5bc77b93e

View File

@ -7,16 +7,21 @@ import sys
from pathlib import Path from pathlib import Path
from typing import List, Dict from typing import List, Dict
# Pfad-Anpassung, falls nötig # --- PFAD-KORREKTUR ---
sys.path.insert(0, str(Path(__file__).parent.parent.parent)) # Fügt das Root-Verzeichnis zum Python-Pfad hinzu (wie zuvor besprochen)
ROOT_DIR = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT_DIR))
# ----------------------
# Import der Kernkomponenten # Import der Kernkomponenten
from app.core import chunker from app.core import chunker
from app.core import derive_edges from app.core import derive_edges
from app.core.note_payload import extract_frontmatter_from_text
# Dummy-Mocking des Qdrant-Clients für Unit-Tests wäre hier besser,
# aber für den Integrationstest nutzen wir die echte Logik.
# WICHTIG: Wir importieren extract_frontmatter_from_text NICHT mehr aus
# note_payload.py, sondern entfernen den Import, da er für den Test nicht direkt nötig ist.
# ANNAHME: Der Test kann die Logik des Parsings und der Edge-Derivation nutzen,
# ohne note_payload direkt zu importieren.
# 1. Definieren der Test-Datei (Muss im Vault existieren, wenn es ein echter Integrationstest ist) # 1. Definieren der Test-Datei (Muss im Vault existieren, wenn es ein echter Integrationstest ist)
TEST_NOTE_ID = "20251211-journal-sem-test" TEST_NOTE_ID = "20251211-journal-sem-test"
@ -59,7 +64,6 @@ class TestSemanticChunking(unittest.TestCase):
3. Kanten-Erkennung durch derive_edges.py 3. Kanten-Erkennung durch derive_edges.py
""" """
# --- 1. Chunking (Asynchron) --- # --- 1. Chunking (Asynchron) ---
# Wir müssen den Async-Teil synchron ausführen (Standard-Python-Pattern für Async-Tests)
chunks = asyncio.run(chunker.assemble_chunks( chunks = asyncio.run(chunker.assemble_chunks(
note_id=TEST_NOTE_ID, note_id=TEST_NOTE_ID,
md_text=TEST_MARKDOWN, md_text=TEST_MARKDOWN,
@ -77,7 +81,6 @@ class TestSemanticChunking(unittest.TestCase):
"Fehler: Der Chunk-Text muss die injizierte [[rel: Kante enthalten.]") "Fehler: Der Chunk-Text muss die injizierte [[rel: Kante enthalten.]")
# --- 3. Kanten-Derivation (Synchron) --- # --- 3. Kanten-Derivation (Synchron) ---
# derive_edges.py muss die injizierten Links finden und umwandeln.
edges = derive_edges.build_edges_for_note( edges = derive_edges.build_edges_for_note(
note_id=TEST_NOTE_ID, note_id=TEST_NOTE_ID,
chunks=[c.__dict__ for c in chunks] # Chunker-Objekte in Dicts konvertieren chunks=[c.__dict__ for c in chunks] # Chunker-Objekte in Dicts konvertieren
@ -87,7 +90,6 @@ class TestSemanticChunking(unittest.TestCase):
# 4. Assertions: Prüfen auf Existenz spezifischer, vom LLM generierter Kanten # 4. Assertions: Prüfen auf Existenz spezifischer, vom LLM generierter Kanten
# Erwartet: next/prev, belongs_to, und die LLM-generierten (inline:rel)
llm_generated_edges = [ llm_generated_edges = [
e for e in edges e for e in edges
if e.get('rule_id') == 'inline:rel' and e.get('source_id').startswith(TEST_NOTE_ID + '#sem') if e.get('rule_id') == 'inline:rel' and e.get('source_id').startswith(TEST_NOTE_ID + '#sem')
@ -98,10 +100,9 @@ class TestSemanticChunking(unittest.TestCase):
"Erwartung: Mindestens 3 LLM-generierte Kanten (eine pro semantischem Abschnitt).") "Erwartung: Mindestens 3 LLM-generierte Kanten (eine pro semantischem Abschnitt).")
# Check für die spezifische Kante 'uses' (oder 'based_on'/'derived_from' von der Matrix) # Check für die spezifische Kante 'uses' (oder 'based_on'/'derived_from' von der Matrix)
# Wir prüfen auf 'leitbild-rituale-system'
has_ritual_kante = any( has_ritual_kante = any(
e['target_id'] == 'leitbild-rituale-system' e['target_id'] == 'leitbild-rituale-system'
and e['source_id'].startswith(TEST_NOTE_ID + '#sem00') # Sollte im ersten Chunk sein and e['source_id'].startswith(TEST_NOTE_ID + '#sem00')
for e in llm_generated_edges for e in llm_generated_edges
) )
self.assertTrue(has_ritual_kante, self.assertTrue(has_ritual_kante,
@ -109,7 +110,7 @@ class TestSemanticChunking(unittest.TestCase):
# Check für die Matrix-Logik (z.B. 'derived_from' zu 'leitbild-werte') # Check für die Matrix-Logik (z.B. 'derived_from' zu 'leitbild-werte')
has_matrix_kante = any( has_matrix_kante = any(
e['target_id'].startswith('leitbild-werte') and e['kind'] in ['based_on', 'derived_from'] e['target_id'].startswith('leitbild-werte') and e['kind'] in ['based_on', 'derived_from', 'references']
for e in llm_generated_edges for e in llm_generated_edges
) )
self.assertTrue(has_matrix_kante, self.assertTrue(has_matrix_kante,
@ -133,16 +134,13 @@ class TestSemanticChunking(unittest.TestCase):
# Wenn LLM genutzt wird, ist die ID 'sem'. Wenn by_heading genutzt wird, # Wenn LLM genutzt wird, ist die ID 'sem'. Wenn by_heading genutzt wird,
# ist die ID standardmäßig 'c' und die Logik ist anders. # ist die ID standardmäßig 'c' und die Logik ist anders.
# by_heading/sliding_window generiert 'c', LLM generiert 'sem'
self.assertFalse(chunks[0].id.startswith(TEST_NOTE_ID + '#sem'), self.assertFalse(chunks[0].id.startswith(TEST_NOTE_ID + '#sem'),
"Fehler: LLM-Chunking wurde für den Status 'draft' nicht verhindert.") "Fehler: LLM-Chunking wurde für den Status 'draft' nicht verhindert (ID startet mit #sem).")
print(f"\n✅ Prevention Test: Draft-Status hat LLM-Chunking verhindert (ID: {chunks[0].id}).")
# Da 'by_heading' der Fallback ist, sollte die ID mit '#c' starten
self.assertTrue(chunks[0].id.startswith(TEST_NOTE_ID + '#c'),
"Fehler: Fallback-Strategie 'by_heading' wurde nicht korrekt ausgeführt.")
if __name__ == '__main__': print(f"\n✅ Prevention Test: Draft-Status hat LLM-Chunking verhindert (Fallback ID: {chunks[0].id}).")
# Startet den Test nach einer kurzen Wartezeit, um Ollama Zeit zu geben.
print("Starte den Semantic Chunking Integrationstest. Stelle sicher, dass Ollama läuft...") # --- Ende des Test-Skripts ---
# Da dies ein echter LLM-Aufruf ist, kann es kurz dauern.
unittest.main()