mindnet/scripts/make_test_vault.py
Lars 4f54e750b2
Some checks failed
Deploy mindnet to llm-node / deploy (push) Failing after 1s
scripts/make_test_vault.py hinzugefügt
2025-09-05 15:35:41 +02:00

246 lines
7.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
make_test_vault.py — Erzeugt einen kleinen, reproduzierbaren Test-Vault für den Markdown-Importer.
Version: 1.0.0 (2025-09-05)
Änderungen:
- Initiale Version mit 4 Szenarien (base, add-targets, change-chunking, cleanup)
- Frontmatter entspricht Parser-Anforderungen: title, id, type, status, created (+ optionale Felder) (vgl. parser.validate_required_frontmatter)
- Inhalte decken Wikilinks, zunächst fehlende Ziele (unresolved), spätere Zielanlage und Re-Chunking ab.
Beschreibung:
Erstellt unter ./test_vault/ eine kleine Ordnerstruktur mit Markdown-Dateien:
- base: Legt 4 Notizen an. Zwei haben Wikilinks, wovon einige zunächst ins Leere zeigen (Ziel-Notizen existieren noch nicht).
- add-targets: Legt die vorher fehlenden Ziel-Notizen an, so dass der Importer Kanten (references/backlink und references_at) auflösen kann.
- change-chunking: Ändert eine bestehende Notiz so, dass sich die Chunk-Grenzen deutlich verschieben (Überschriften + Textblöcke). Dient zum Test, ob der Importer Notes/Chunks/Edges sauber nachzieht.
- cleanup: Löscht den gesamten test_vault wieder.
Aufruf:
python3 -m scripts.make_test_vault --scenario base
python3 -m scripts.make_test_vault --scenario add-targets
python3 -m scripts.make_test_vault --scenario change-chunking
python3 -m scripts.make_test_vault --scenario cleanup
Hinweise:
- Dieses Skript erzeugt KEINE Qdrant-Daten; es schreibt nur Markdown-Dateien.
- Zum Testen:
1) base erzeugen → Importer (dry-run) → Audit vergleichen.
2) add-targets erzeugen → Importer erneut laufen lassen → prüfen, ob vormals „unresolved“ jetzt aufgelöst wurden (edges & edges_at).
3) change-chunking ausführen → Importer mit --apply → prüfen, ob Chunks/Edges umgezogen/aktualisiert wurden.
- Verwende beim Importer denselben Vault-Pfad: --vault ./test_vault
- Virtuelle Umgebung: Für dieses Skript selbst nicht nötig; für den Importer natürlich weiterhin in deinem venv laufen.
"""
from __future__ import annotations
import argparse
import os
import shutil
from pathlib import Path
from datetime import datetime
ROOT = Path(__file__).resolve().parents[1] # Projektwurzel (.. /mindnet)
VAULT = ROOT / "test_vault"
# ---------- Hilfsfunktionen ----------
def write_file(path: Path, content: str):
path.parent.mkdir(parents=True, exist_ok=True)
with open(path, "w", encoding="utf-8") as f:
f.write(content)
def iso_now():
return datetime.now().isoformat(timespec="seconds")
# ---------- Inhalte (Szenario-Varianten) ----------
def file_index_base() -> str:
# Enthält Links auf bestehende und noch NICHT bestehende Ziele
return f"""---
title: "Index Mini-Testvault"
id: "test-index"
type: "concept"
status: "draft"
created: {iso_now()}
tags: ["area/test","type/concept"]
---
## Überblick
Dies ist der kleine Test-Vault.
## Verweise
- [[test-alpha]] (existiert)
- [[test-beta]] (existiert)
- [[test-gamma]] (existiert)
- [[test-delta]] (FEHLT zunächst — wird erst in add-targets angelegt)
"""
def file_alpha_base() -> str:
# Hat Wikilinks auf beta (existiert) und epsilon (fehlt zunächst)
return f"""---
title: "Alpha"
id: "test-alpha"
type: "concept"
status: "draft"
created: {iso_now()}
tags: ["area/test","type/concept"]
---
## Abschnitt A
Alpha verweist auf [[test-beta]] und auf [[test-epsilon]] (FEHLT zunächst).
## Abschnitt B
Noch etwas Text, damit beim Re-Chunking später Grenzen sichtbar werden.
"""
def file_beta_base() -> str:
# Kurze Notiz ohne Links
return f"""---
title: "Beta"
id: "test-beta"
type: "concept"
status: "draft"
created: {iso_now()}
tags: ["area/test","type/concept"]
---
Beta hat zunächst keine Links.
"""
def file_gamma_base() -> str:
# Viele Abschnitte → erzeugt mehrere Chunks
return f"""---
title: "Gamma"
id: "test-gamma"
type: "concept"
status: "draft"
created: {iso_now()}
tags: ["area/test","type/concept"]
---
## Einleitung
Dieser Abschnitt enthält einen Link zu [[test-index]].
## Details
Gamma liefert Details. Hier noch ein Link zu [[test-beta]].
## Weitere Hinweise
Hier steht Text, damit die Chunker-Logik genug Material hat.
"""
def file_delta_added() -> str:
# Wird erst im Szenario add-targets erstellt (auflösen von vormals unresolved [[test-delta]])
return f"""---
title: "Delta (neu angelegt)"
id: "test-delta"
type: "concept"
status: "draft"
created: {iso_now()}
tags: ["area/test","type/concept"]
---
Delta wurde nachträglich angelegt, um ehemals leere Links aufzulösen.
"""
def file_epsilon_added() -> str:
# Wird erst im Szenario add-targets erstellt (auflösen von [[test-epsilon]] aus Alpha)
return f"""---
title: "Epsilon (neu angelegt)"
id: "test-epsilon"
type: "concept"
status: "draft"
created: {iso_now()}
tags: ["area/test","type/concept"]
---
Epsilon existiert nun und kann referenziert werden.
"""
def file_gamma_changed_chunking() -> str:
# Ersetzt die ursprüngliche Gamma-Datei mit deutlich mehr (und anders geschnittenen) Abschnitten,
# so dass sich die Chunk-Grenzen ändern.
return f"""---
title: "Gamma (rechunked)"
id: "test-gamma"
type: "concept"
status: "draft"
created: {iso_now()}
tags: ["area/test","type/concept"]
---
# Einleitung (H1 statt H2)
Kurzer Teaser. Verweis auf [[test-index]] bleibt bestehen.
## Teil 1 Kontext
Mehr Text. Dieser Abschnitt ist länger und soll den ursprünglichen „Details“-Block ersetzen.
Außerdem Verweis auf [[test-beta]].
## Teil 2 Beispiele
- Beispiel 1: Ein etwas längerer Listenpunkt mit Beschreibung.
- Beispiel 2: Noch ein Punkt.
- Beispiel 3: Und noch einer.
## Teil 3 Fazit
Zusammenfassung und ggf. ein weiterer Verweis auf [[test-alpha]].
"""
# ---------- Szenarien ausführen ----------
def scenario_base():
# Frisch anlegen / überschreiben
(VAULT / "notes").mkdir(parents=True, exist_ok=True)
write_file(VAULT / "notes" / "index.md", file_index_base())
write_file(VAULT / "notes" / "alpha.md", file_alpha_base())
write_file(VAULT / "notes" / "beta.md", file_beta_base())
write_file(VAULT / "notes" / "gamma.md", file_gamma_base())
print(f"[base] Angelegt: {VAULT}")
def scenario_add_targets():
# Nur neue Ziele hinzufügen (delta, epsilon)
if not VAULT.exists():
print("test_vault fehlt bitte erst --scenario base ausführen.")
return
write_file(VAULT / "notes" / "delta.md", file_delta_added())
write_file(VAULT / "notes" / "epsilon.md", file_epsilon_added())
print("[add-targets] Neue Zielnotizen delta/epsilon angelegt.")
def scenario_change_chunking():
# Gamma ersetzen, um Chunk-Grenzen zu verschieben
if not VAULT.exists():
print("test_vault fehlt bitte erst --scenario base ausführen.")
return
write_file(VAULT / "notes" / "gamma.md", file_gamma_changed_chunking())
print("[change-chunking] gamma.md geändert (deutlich andere Abschnittsstruktur).")
def scenario_cleanup():
if VAULT.exists():
shutil.rmtree(VAULT)
print("[cleanup] test_vault gelöscht.")
else:
print("[cleanup] nichts zu tun test_vault existiert nicht.")
# ---------- CLI ----------
def main():
ap = argparse.ArgumentParser()
ap.add_argument(
"--scenario",
required=True,
choices=["base", "add-targets", "change-chunking", "cleanup"],
help="Welches Setup erzeugt werden soll."
)
args = ap.parse_args()
if args.scenario == "base":
scenario_base()
elif args.scenario == "add-targets":
scenario_add_targets()
elif args.scenario == "change-chunking":
scenario_change_chunking()
elif args.scenario == "cleanup":
scenario_cleanup()
if __name__ == "__main__":
main()