code header

This commit is contained in:
Lars 2025-12-15 15:40:39 +01:00
parent ec759dd1dc
commit 83bb18b6a7
42 changed files with 469 additions and 615 deletions

View File

@ -1,17 +1,10 @@
""" """
app mindnet API package FILE: app/__init__.py
DESCRIPTION: Paket-Initialisierung.
Zweck: VERSION: 0.1.0
Markiert 'app/' als Python-Paket, damit 'from app.main import create_app' STATUS: Active
in Tests und Skripten funktioniert. DEPENDENCIES: None
Kompatibilität: LAST_ANALYSIS: 2025-12-15
Python 3.12+
Version:
0.1.0 (Erstanlage)
Stand:
2025-10-07
Hinweise:
Keine Logik nur Paketinitialisierung.
""" """
__version__ = "0.1.0" __version__ = "0.1.0"

View File

@ -1,6 +1,10 @@
""" """
app/config.py zentrale Konfiguration FILE: app/config.py
Version: 0.4.0 (WP-06 Complete) DESCRIPTION: Zentrale Pydantic-Konfiguration (Env-Vars für Qdrant, LLM, Retriever).
VERSION: 0.4.0
STATUS: Active
DEPENDENCIES: os, functools, pathlib
LAST_ANALYSIS: 2025-12-15
""" """
from __future__ import annotations from __future__ import annotations
import os import os

View File

@ -1,11 +1,11 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
""" """
app/core/chunk_payload.py (Mindnet V2 types.yaml authoritative) FILE: app/core/chunk_payload.py
- neighbors_prev / neighbors_next sind Listen ([], [id]). DESCRIPTION: Baut das JSON-Objekt für 'mindnet_chunks'. Inkludiert Nachbarschafts-IDs (prev/next) und Titel.
- retriever_weight / chunk_profile kommen aus types.yaml (Frontmatter wird ignoriert). VERSION: 2.0.0
- Fallbacks: defaults.* in types.yaml; sonst 1.0 / "default". STATUS: Active
- WP-11 Update: Injects 'title' into chunk payload for Discovery Service. DEPENDENCIES: yaml, os
EXTERNAL_CONFIG: config/types.yaml
LAST_ANALYSIS: 2025-12-15
""" """
from __future__ import annotations from __future__ import annotations
from typing import Any, Dict, List, Optional from typing import Any, Dict, List, Optional

View File

@ -1,3 +1,13 @@
"""
FILE: app/core/chunker.py
DESCRIPTION: Zerlegt Texte in Chunks (Sliding Window oder nach Headings). Orchestriert die Smart-Edge-Allocation via SemanticAnalyzer.
VERSION: 2.5.0
STATUS: Active
DEPENDENCIES: app.services.semantic_analyzer, app.core.derive_edges, markdown_it, yaml, asyncio
EXTERNAL_CONFIG: config/types.yaml
LAST_ANALYSIS: 2025-12-15
"""
from __future__ import annotations from __future__ import annotations
from dataclasses import dataclass from dataclasses import dataclass
from typing import List, Dict, Optional, Tuple, Any, Set from typing import List, Dict, Optional, Tuple, Any, Set

View File

@ -1,26 +1,11 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
""" """
Modul: app/core/derive_edges.py FILE: app/core/derive_edges.py
Zweck: DESCRIPTION: Extrahiert Graph-Kanten aus Text. Unterstützt Wikilinks, Inline-Relations ([[rel:type|target]]) und Obsidian Callouts.
- Bewahrt bestehende Edgelogik (belongs_to, prev/next, references, backlink) VERSION: 2.0.0
- Ergänzt typenbasierte Default-Kanten (edge_defaults aus config/types.yaml) STATUS: Active
- Unterstützt "typed inline relations": DEPENDENCIES: re, os, yaml, typing
* [[rel:KIND | Target]] EXTERNAL_CONFIG: config/types.yaml
* [[rel:KIND Target]] LAST_ANALYSIS: 2025-12-15
* rel: KIND [[Target]]
- Unterstützt Obsidian-Callouts:
* > [!edge] KIND: [[Target]] [[Target2]] ...
Kompatibilität:
- build_edges_for_note(...) Signatur unverändert
- rule_id Werte:
* structure:belongs_to
* structure:order
* explicit:wikilink
* inline:rel
* callout:edge
* edge_defaults:<type>:<relation>
* derived:backlink
""" """
from __future__ import annotations from __future__ import annotations

View File

@ -1,17 +1,10 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
""" """
app/core/graph_adapter.py Adjazenzaufbau & Subgraph-Expansion FILE: app/core/graph_adapter.py
DESCRIPTION: Lädt Kanten aus Qdrant und baut einen In-Memory Subgraphen für Scoring (Centrality) und Explanation.
Zweck: VERSION: 0.4.0
Baut aus Qdrant-Edges (Collection: *_edges) einen leichten In-Memory-Graph. STATUS: Active
DEPENDENCIES: qdrant_client, app.core.qdrant
Kompatibilität: LAST_ANALYSIS: 2025-12-15
- WP-04a: Liefert Scores (edge_bonus, centrality).
- WP-04b: Liefert jetzt auch Struktur-Daten für Erklärungen (Reverse-Lookup).
Version:
0.4.0 (Update für WP-04b: Reverse Adjacency für Explainability)
""" """
from __future__ import annotations from __future__ import annotations

View File

@ -1,8 +1,11 @@
""" """
app/core/ingestion.py FILE: app/core/ingestion.py
DESCRIPTION: Haupt-Ingestion-Logik. Liest Markdown, prüft Hashes (Change Detection), zerlegt in Chunks und schreibt in Qdrant.
Zentraler Service für die Transformation von Markdown-Dateien in Qdrant-Objekte. VERSION: 2.5.2
Version: 2.5.2 (Full Feature: Change Detection + Robust IO + Clean Config) STATUS: Active
DEPENDENCIES: app.core.parser, app.core.note_payload, app.core.chunker, app.core.derive_edges, app.core.qdrant*, app.services.embeddings_client
EXTERNAL_CONFIG: config/types.yaml
LAST_ANALYSIS: 2025-12-15
""" """
import os import os
import logging import logging

View File

@ -1,17 +1,11 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
""" """
Modul: app/core/note_payload.py FILE: app/core/note_payload.py
Version: 2.1.0 (WP-11 Update: Aliases support) DESCRIPTION: Baut das JSON-Objekt für 'mindnet_notes'. Wendet Vererbung für Configs an (Frontmatter > Type > Default).
VERSION: 2.1.0
Zweck STATUS: Active
----- DEPENDENCIES: yaml, os, json, pathlib
Erzeugt ein robustes Note-Payload. Werte wie `retriever_weight`, `chunk_profile` EXTERNAL_CONFIG: config/types.yaml
und `edge_defaults` werden in folgender Priorität bestimmt: LAST_ANALYSIS: 2025-12-15
1) Frontmatter (Note)
2) Typ-Registry (config/types.yaml: types.<type>.*)
3) Registry-Defaults (config/types.yaml: defaults.*)
4) ENV-Defaults (MINDNET_DEFAULT_RETRIEVER_WEIGHT / MINDNET_DEFAULT_CHUNK_PROFILE)
""" """
from __future__ import annotations from __future__ import annotations

View File

@ -1,43 +1,10 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
""" """
Modul: app/core/parser.py FILE: app/core/parser.py
Version: 1.7.1 (fault-tolerant, API-kompatibel) DESCRIPTION: Liest Markdown-Dateien fehlertolerant (Encoding-Fallback). Trennt Frontmatter (YAML) vom Body.
Datum: 2025-10-01 VERSION: 1.7.1
STATUS: Active
Zweck DEPENDENCIES: yaml, re, dataclasses, json, io, os
----- LAST_ANALYSIS: 2025-12-15
Fehlertolerantes Einlesen von Markdown-Dateien mit YAML-Frontmatter.
Kompatibel zur bisherigen Parser-API, aber robust gegenüber Nicht-UTF-8-Dateien:
- Versucht nacheinander: utf-8 utf-8-sig cp1252 latin-1.
- Bei Fallback wird ein JSON-Warnhinweis auf stdout ausgegeben; der Import bricht NICHT ab.
- YAML-Frontmatter wird mit '---' am Anfang und '---' als Abschluss erkannt.
- extract_wikilinks() normalisiert [[id#anchor|label]] → 'id'.
Öffentliche API (kompatibel):
- class ParsedNote(frontmatter: dict, body: str, path: str)
- read_markdown(path) -> ParsedNote | None
- normalize_frontmatter(fm) -> dict
- validate_required_frontmatter(fm, required: tuple[str,...]=("id","title")) -> None
- extract_wikilinks(text) -> list[str]
- FRONTMATTER_RE (Kompatibilitäts-Konstante; Regex für '---'-Zeilen)
Beispiele
---------
from app.core.parser import read_markdown, normalize_frontmatter, validate_required_frontmatter
parsed = read_markdown("./vault/30_projects/project-demo.md")
fm = normalize_frontmatter(parsed.frontmatter)
validate_required_frontmatter(fm)
body = parsed.body
from app.core.parser import extract_wikilinks
links = extract_wikilinks(body)
Abhängigkeiten
--------------
- PyYAML (yaml)
Lizenz: MIT (projektintern)
""" """
from __future__ import annotations from __future__ import annotations

View File

@ -1,28 +1,10 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
""" """
app/core/qdrant.py FILE: app/core/qdrant.py
Version: 2.2.0 (2025-11-11) DESCRIPTION: Qdrant-Client Factory und Schema-Management. Erstellt Collections und Payload-Indizes.
VERSION: 2.2.0
Aufgabe STATUS: Active
------- DEPENDENCIES: qdrant_client, dataclasses, os
- Zentraler Qdrant-Zugriff (Client, Config) LAST_ANALYSIS: 2025-12-15
- Collection-Anlage (notes/chunks/edges)
- **Payload-Indizes sicherstellen** (idempotent)
Hinweis
-------
Diese Datei ist als Drop-in-Ersatz gedacht, falls in deinem Projekt noch keine
robuste ensure_payload_indexes()-Implementierung vorliegt. Die Signaturen
bleiben kompatibel zu scripts.import_markdown und scripts.reset_qdrant.
API-Notizen
-----------
- Payload-Indizes werden mit `create_payload_index` angelegt.
- Typen stammen aus `qdrant_client.http.models.PayloadSchemaType`:
KEYWORD | TEXT | INTEGER | FLOAT | BOOL | GEO | DATETIME
- Für häufige Filterfelder (note_id, kind, scope, type, tags, ...) legen wir
Indizes an. Das ist laut Qdrant-Doku Best Practice für performante Filter.
""" """
from __future__ import annotations from __future__ import annotations

View File

@ -1,18 +1,10 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
""" """
app/core/qdrant_points.py - robust points helpers for Qdrant FILE: app/core/qdrant_points.py
DESCRIPTION: Object-Mapper für Qdrant. Konvertiert JSON-Payloads (Notes, Chunks, Edges) in PointStructs und generiert deterministische UUIDs.
- Single source of truth for building PointStruct for notes/chunks/edges VERSION: 1.5.0
- Backward-compatible payloads for edges STATUS: Active
- Handles both Single-Vector and Named-Vector collections DEPENDENCIES: qdrant_client, uuid, os
- Deterministic overrides via ENV to avoid auto-detection traps: LAST_ANALYSIS: 2025-12-15
* NOTES_VECTOR_NAME, CHUNKS_VECTOR_NAME, EDGES_VECTOR_NAME
* MINDNET_VECTOR_NAME (fallback)
> Set to a concrete name (e.g. "text") to force Named-Vector with that name
> Set to "__single__" (or "single") to force Single-Vector
Version: 1.5.0 (2025-11-08)
""" """
from __future__ import annotations from __future__ import annotations
import os import os

View File

@ -1,8 +1,10 @@
""" """
app/core/retriever.py Hybrider Such-Algorithmus FILE: app/core/retriever.py
DESCRIPTION: Implementiert die Hybrid-Suche (Vektor + Graph-Expansion) und das Scoring-Modell (Explainability).
Version: VERSION: 0.5.3
0.5.3 (WP-06 Fix: Populate 'payload' in QueryHit for meta-data access) STATUS: Active
DEPENDENCIES: app.config, app.models.dto, app.core.qdrant*, app.services.embeddings_client, app.core.graph_adapter
LAST_ANALYSIS: 2025-12-15
""" """
from __future__ import annotations from __future__ import annotations

View File

@ -1,30 +1,11 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
""" """
Modul: app/core/type_registry.py FILE: app/core/type_registry.py
Version: 1.0.0 DESCRIPTION: Loader für types.yaml. Achtung: Wird in der aktuellen Pipeline meist durch lokale Loader in 'ingestion.py' oder 'note_payload.py' umgangen.
Datum: 2025-11-08 VERSION: 1.0.0
STATUS: Deprecated (Redundant)
Zweck DEPENDENCIES: yaml, os, functools
----- EXTERNAL_CONFIG: config/types.yaml
Lädt eine optionale Typ-Registry (config/types.yaml) und stellt LAST_ANALYSIS: 2025-12-15
komfortable Zugriffsfunktionen bereit. Die Registry ist *optional*:
- Fehlt die Datei oder ist das YAML defekt, wird ein konservativer
Default (Typ "concept") verwendet und es wird eine Warnung ausgegeben.
- Änderungen an der Datei greifen nach einem Neustart des Prozesses.
Öffentliche API
---------------
- load_type_registry(path: str = "config/types.yaml") -> dict
- get_type_config(note_type: str, reg: dict) -> dict
- resolve_note_type(fm_type: str | None, reg: dict) -> str
- effective_chunk_profile(note_type: str, reg: dict) -> str | None
- profile_overlap(profile: str | None) -> tuple[int,int] # nur Overlap-Empfehlung
Hinweis
-------
Die Registry steuert KEINE Breaking Changes. Ohne Datei/Typ bleibt das
Verhalten exakt wie im Release-Stand 20251105.
""" """
from __future__ import annotations from __future__ import annotations

View File

@ -1,23 +0,0 @@
"""
Version 0.1
"""
from __future__ import annotations
from typing import List
from functools import lru_cache
from .config import get_settings
@lru_cache
def _load_model():
from sentence_transformers import SentenceTransformer
settings = get_settings()
model = SentenceTransformer(settings.MODEL_NAME, device="cpu")
return model
def embed_texts(texts: List[str]) -> list[list[float]]:
model = _load_model()
texts = [t if isinstance(t, str) else str(t) for t in texts]
vecs = model.encode(texts, normalize_embeddings=True, convert_to_numpy=False)
return [list(map(float, v)) for v in vecs]

View File

@ -1,3 +1,12 @@
"""
FILE: app/frontend/ui.py
DESCRIPTION: Main Entrypoint für Streamlit. Router, der basierend auf Sidebar-Auswahl die Module (Chat, Editor, Graph) lädt.
VERSION: 2.6.0
STATUS: Active
DEPENDENCIES: streamlit, ui_config, ui_sidebar, ui_chat, ui_editor, ui_graph_service, ui_graph*, ui_graph_cytoscape
LAST_ANALYSIS: 2025-12-15
"""
import streamlit as st import streamlit as st
import uuid import uuid

View File

@ -1,3 +1,12 @@
"""
FILE: app/frontend/ui_api.py
DESCRIPTION: Wrapper für Backend-Calls (Chat, Ingest, Feedback). Kapselt requests und Error-Handling.
VERSION: 2.6.0
STATUS: Active
DEPENDENCIES: requests, streamlit, ui_config
LAST_ANALYSIS: 2025-12-15
"""
import requests import requests
import streamlit as st import streamlit as st
from ui_config import CHAT_ENDPOINT, INGEST_ANALYZE_ENDPOINT, INGEST_SAVE_ENDPOINT, FEEDBACK_ENDPOINT, API_TIMEOUT from ui_config import CHAT_ENDPOINT, INGEST_ANALYZE_ENDPOINT, INGEST_SAVE_ENDPOINT, FEEDBACK_ENDPOINT, API_TIMEOUT

View File

@ -1,3 +1,12 @@
"""
FILE: app/frontend/ui_callbacks.py
DESCRIPTION: Event-Handler für UI-Interaktionen. Implementiert den Übergang vom Graphen zum Editor (State Transfer).
VERSION: 2.6.0
STATUS: Active
DEPENDENCIES: streamlit, os, ui_utils
LAST_ANALYSIS: 2025-12-15
"""
import streamlit as st import streamlit as st
import os import os
from ui_utils import build_markdown_doc from ui_utils import build_markdown_doc

View File

@ -1,3 +1,12 @@
"""
FILE: app/frontend/ui_chat.py
DESCRIPTION: Chat-UI. Rendert Nachrichtenverlauf, Quellen-Expanders mit Feedback-Buttons und delegiert bei Bedarf an den Editor.
VERSION: 2.6.0
STATUS: Active
DEPENDENCIES: streamlit, ui_api, ui_editor
LAST_ANALYSIS: 2025-12-15
"""
import streamlit as st import streamlit as st
from ui_api import send_chat_message, submit_feedback from ui_api import send_chat_message, submit_feedback
from ui_editor import render_draft_editor from ui_editor import render_draft_editor

View File

@ -1,3 +1,12 @@
"""
FILE: app/frontend/ui_config.py
DESCRIPTION: Zentrale Konfiguration für das Frontend. Definiert API-Endpoints, Timeouts und Graph-Styles (Farben).
VERSION: 2.6.0
STATUS: Active
DEPENDENCIES: os, hashlib, dotenv, pathlib
LAST_ANALYSIS: 2025-12-15
"""
import os import os
import hashlib import hashlib
from dotenv import load_dotenv from dotenv import load_dotenv

View File

@ -1,3 +1,11 @@
"""
FILE: app/frontend/ui_editor.py
DESCRIPTION: Markdown-Editor mit Live-Vorschau und Metadaten-Feldern. Unterstützt Intelligence-Features (Link-Vorschläge) und unterscheidet Create/Update-Modus.
VERSION: 2.6.0
STATUS: Active
DEPENDENCIES: streamlit, uuid, re, datetime, ui_utils, ui_api
LAST_ANALYSIS: 2025-12-15
"""
import streamlit as st import streamlit as st
import uuid import uuid
import re import re

View File

@ -1,3 +1,12 @@
"""
FILE: app/frontend/ui_graph.py
DESCRIPTION: Legacy Graph-Explorer (Streamlit-Agraph). Implementiert Physik-Simulation (BarnesHut) und direkten Editor-Sprung.
VERSION: 2.6.0
STATUS: Maintenance (Active Fallback)
DEPENDENCIES: streamlit, streamlit_agraph, qdrant_client, ui_config, ui_callbacks
LAST_ANALYSIS: 2025-12-15
"""
import streamlit as st import streamlit as st
from streamlit_agraph import agraph, Config from streamlit_agraph import agraph, Config
from qdrant_client import models from qdrant_client import models

View File

@ -1,3 +1,12 @@
"""
FILE: app/frontend/ui_graph_cytoscape.py
DESCRIPTION: Moderner Graph-Explorer (Cytoscape.js). Features: COSE-Layout, Deep-Linking (URL Params), Active Inspector Pattern (CSS-Styling ohne Re-Render).
VERSION: 2.6.0
STATUS: Active
DEPENDENCIES: streamlit, st_cytoscape, qdrant_client, ui_config, ui_callbacks
LAST_ANALYSIS: 2025-12-15
"""
import streamlit as st import streamlit as st
from st_cytoscape import cytoscape from st_cytoscape import cytoscape
from qdrant_client import models from qdrant_client import models

View File

@ -1,3 +1,12 @@
"""
FILE: app/frontend/ui_graph_service.py
DESCRIPTION: Data Layer für den Graphen. Greift direkt auf Qdrant zu (Performance), um Knoten/Kanten zu laden und Texte zu rekonstruieren ("Stitching").
VERSION: 2.6.0
STATUS: Active
DEPENDENCIES: qdrant_client, streamlit_agraph, ui_config, re
LAST_ANALYSIS: 2025-12-15
"""
import re import re
from qdrant_client import QdrantClient, models from qdrant_client import QdrantClient, models
from streamlit_agraph import Node, Edge from streamlit_agraph import Node, Edge

View File

@ -1,3 +1,12 @@
"""
FILE: app/frontend/ui_sidebar.py
DESCRIPTION: Rendert die Sidebar. Steuert den Modus-Wechsel (Chat/Editor/Graph) und globale Settings (Top-K).
VERSION: 2.6.0
STATUS: Active
DEPENDENCIES: streamlit, ui_utils, ui_config
LAST_ANALYSIS: 2025-12-15
"""
import streamlit as st import streamlit as st
from ui_utils import load_history_from_logs from ui_utils import load_history_from_logs
from ui_config import HISTORY_FILE from ui_config import HISTORY_FILE

View File

@ -1,3 +1,12 @@
"""
FILE: app/frontend/ui_utils.py
DESCRIPTION: String-Utilities. Parser für Markdown/YAML (LLM-Healing) und Helper für History-Loading.
VERSION: 2.6.0
STATUS: Active
DEPENDENCIES: re, yaml, unicodedata, json, datetime
LAST_ANALYSIS: 2025-12-15
"""
import re import re
import yaml import yaml
import unicodedata import unicodedata

View File

@ -1,172 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Modul: app/graph/service.py
Version: 0.1.0
Datum: 2025-09-10
Zweck
-----
Leichtgewichtiger Graph-Layer über Qdrant:
- get_note(note_id)
- get_chunks(note_id)
- neighbors(source_id, kinds=[...], scope=['note','chunk'], depth=1)
- walk_bfs(source_id, kinds, max_depth)
- context_for_note(note_id, max_neighbors): heuristische Kontextsammlung
Hinweise
--------
- Nutzt die bestehenden Collections <prefix>_notes/_chunks/_edges.
- Edges werden über Payload-Felder (`kind`, `source_id`, `target_id`) abgefragt.
"""
from __future__ import annotations
from typing import List, Dict, Any, Optional, Iterable, Set, Tuple
from qdrant_client.http import models as rest
from app.core.qdrant import QdrantConfig, get_client
def _cols(prefix: str):
return f"{prefix}_notes", f"{prefix}_chunks", f"{prefix}_edges"
class GraphService:
def __init__(self, cfg: Optional[QdrantConfig] = None, prefix: Optional[str] = None):
self.cfg = cfg or QdrantConfig.from_env()
if prefix:
self.cfg.prefix = prefix
self.client = get_client(self.cfg)
self.notes_col, self.chunks_col, self.edges_col = _cols(self.cfg.prefix)
# ------------------------ fetch helpers ------------------------
def _scroll(self, col: str, flt: Optional[rest.Filter] = None, limit: int = 256):
out = []
nextp = None
while True:
pts, nextp = self.client.scroll(
collection_name=col,
with_payload=True,
with_vectors=False,
limit=limit,
offset=nextp,
scroll_filter=flt,
)
if not pts:
break
out.extend(pts)
if nextp is None:
break
return out
# ------------------------ public API ---------------------------
def get_note(self, note_id: str) -> Optional[Dict[str, Any]]:
f = rest.Filter(must=[rest.FieldCondition(key="note_id", match=rest.MatchValue(value=note_id))])
pts, _ = self.client.scroll(self.notes_col, with_payload=True, with_vectors=False, limit=1, scroll_filter=f)
return (pts[0].payload or None) if pts else None
def get_chunks(self, note_id: str) -> List[Dict[str, Any]]:
f = rest.Filter(must=[rest.FieldCondition(key="note_id", match=rest.MatchValue(value=note_id))])
pts = self._scroll(self.chunks_col, f)
# Sortierung analog Export
def key(pl):
p = pl.payload or {}
s = p.get("seq") or 0
ci = p.get("chunk_index") or 0
n = 0
cid = p.get("chunk_id") or ""
if isinstance(cid, str) and "#" in cid:
try:
n = int(cid.rsplit("#", 1)[-1])
except Exception:
n = 0
return (int(s), int(ci), n)
pts_sorted = sorted(pts, key=key)
return [p.payload or {} for p in pts_sorted]
def neighbors(self, source_id: str, kinds: Optional[Iterable[str]] = None,
scope: Optional[Iterable[str]] = None, depth: int = 1) -> Dict[str, List[Dict[str, Any]]]:
"""
Liefert eingehende & ausgehende Nachbarn (nur nach kind gefiltert).
depth==1: direkte Kanten.
"""
kinds = list(kinds) if kinds else None
must = [rest.FieldCondition(key="source_id", match=rest.MatchValue(value=source_id))]
if kinds:
must.append(rest.FieldCondition(key="kind", match=rest.MatchAny(any=kinds)))
f = rest.Filter(must=must)
edges = self._scroll(self.edges_col, f)
out = {"out": [], "in": []}
for e in edges:
out["out"].append(e.payload or {})
# Inverse Richtung (eingehend)
must_in = [rest.FieldCondition(key="target_id", match=rest.MatchValue(value=source_id))]
if kinds:
must_in.append(rest.FieldCondition(key="kind", match=rest.MatchAny(any=kinds)))
f_in = rest.Filter(must=must_in)
edges_in = self._scroll(self.edges_col, f_in)
for e in edges_in:
out["in"].append(e.payload or {})
return out
def walk_bfs(self, source_id: str, kinds: Iterable[str], max_depth: int = 2) -> Set[str]:
visited: Set[str] = {source_id}
frontier: Set[str] = {source_id}
kinds = list(kinds)
for _ in range(max_depth):
nxt: Set[str] = set()
for s in frontier:
neigh = self.neighbors(s, kinds=kinds)
for e in neigh["out"]:
t = e.get("target_id")
if isinstance(t, str) and t not in visited:
visited.add(t)
nxt.add(t)
frontier = nxt
if not frontier:
break
return visited
def context_for_note(self, note_id: str, kinds: Iterable[str] = ("references","backlink"), max_neighbors: int = 12) -> Dict[str, Any]:
"""
Heuristischer Kontext: eigene Chunks + Nachbarn nach Kantenarten, dedupliziert.
"""
note = self.get_note(note_id) or {}
chunks = self.get_chunks(note_id)
neigh = self.neighbors(note_id, kinds=list(kinds))
targets = []
for e in neigh["out"]:
t = e.get("target_id")
if isinstance(t, str):
targets.append(t)
for e in neigh["in"]:
s = e.get("source_id")
if isinstance(s, str):
targets.append(s)
# de-dupe
seen = set()
uniq = []
for t in targets:
if t not in seen:
seen.add(t)
uniq.append(t)
uniq = uniq[:max_neighbors]
neighbor_notes = [self.get_note(t) for t in uniq]
return {
"note": note,
"chunks": chunks,
"neighbors": [n for n in neighbor_notes if n],
"edges_out": neigh["out"],
"edges_in": neigh["in"],
}
# Optional: Mini-CLI
if __name__ == "__main__": # pragma: no cover
import argparse, json
ap = argparse.ArgumentParser()
ap.add_argument("--prefix", help="Collection-Prefix (überschreibt ENV)")
ap.add_argument("--note-id", required=True)
ap.add_argument("--neighbors", action="store_true", help="Nur Nachbarn anzeigen")
args = ap.parse_args()
svc = GraphService(prefix=args.prefix)
if args.neighbors:
out = svc.neighbors(args.note_id, kinds=["references","backlink","prev","next","belongs_to"])
else:
out = svc.context_for_note(args.note_id)
print(json.dumps(out, ensure_ascii=False, indent=2))

View File

@ -1,6 +1,12 @@
""" """
app/main.py mindnet API bootstrap FILE: app/main.py
DESCRIPTION: Bootstrap der FastAPI Anwendung. Inkludiert Router und Middleware.
VERSION: 0.6.0
STATUS: Active
DEPENDENCIES: app.config, app.routers.* (embed, qdrant, query, graph, tools, feedback, chat, ingest, admin)
LAST_ANALYSIS: 2025-12-15
""" """
from __future__ import annotations from __future__ import annotations
from fastapi import FastAPI from fastapi import FastAPI
from .config import get_settings from .config import get_settings

View File

@ -1,14 +1,10 @@
""" """
app/models/dto.py Pydantic-Modelle (DTOs) für WP-04/WP-05/WP-06 FILE: app/models/dto.py
DESCRIPTION: Pydantic-Modelle (DTOs) für Request/Response Bodies. Definiert das API-Schema.
Zweck: VERSION: 0.6.2
Laufzeit-Modelle für FastAPI (Requests/Responses). STATUS: Active
WP-06 Update: Intent & Intent-Source in ChatResponse. DEPENDENCIES: pydantic, typing, uuid
LAST_ANALYSIS: 2025-12-15
Version:
0.6.2 (WP-06: Decision Engine Transparency, Erweiterung des Feeback Request)
Stand:
2025-12-09
""" """
from __future__ import annotations from __future__ import annotations

View File

@ -1,20 +1,10 @@
""" """
app/routers/admin.py Admin-/Monitoring-Endpunkte (optional) FILE: app/routers/admin.py
DESCRIPTION: Monitoring-Endpunkt. Zeigt Qdrant-Collection-Counts und geladene Config.
Zweck: VERSION: 0.1.0
Liefert einfache Kennzahlen zu Collections (Counts) und Config. STATUS: Active (Optional)
Kompatibilität: DEPENDENCIES: qdrant_client, app.config
Python 3.12+, FastAPI 0.110+, qdrant-client 1.x LAST_ANALYSIS: 2025-12-15
Version:
0.1.0 (Erstanlage)
Stand:
2025-10-07
Bezug:
- Qdrant Collections: *_notes, *_chunks, *_edges
Nutzung:
app.include_router(admin.router, prefix="/admin", tags=["admin"])
Änderungsverlauf:
0.1.0 (2025-10-07) Erstanlage.
""" """
from __future__ import annotations from __future__ import annotations

View File

@ -1,6 +1,11 @@
""" """
app/routers/chat.py RAG Endpunkt FILE: app/routers/chat.py
Version: 2.5.0 (Fix: Question Detection protects against False-Positive Interviews) DESCRIPTION: Haupt-Chat-Interface (RAG & Interview). Enthält Intent-Router (Keywords/LLM) und Prompt-Construction.
VERSION: 2.5.0
STATUS: Active
DEPENDENCIES: app.config, app.models.dto, app.services.llm_service, app.core.retriever, app.services.feedback_service
EXTERNAL_CONFIG: config/decision_engine.yaml, config/types.yaml
LAST_ANALYSIS: 2025-12-15
""" """
from fastapi import APIRouter, HTTPException, Depends from fastapi import APIRouter, HTTPException, Depends

View File

@ -1,5 +1,10 @@
""" """
Version 0.1 FILE: app/routers/embed_router.py
DESCRIPTION: Exponiert die lokale Embedding-Funktion als API-Endpunkt.
VERSION: 0.1.0
STATUS: Active
DEPENDENCIES: app.embeddings, pydantic
LAST_ANALYSIS: 2025-12-15
""" """
from __future__ import annotations from __future__ import annotations

View File

@ -1,6 +1,10 @@
""" """
app/routers/feedback.py FILE: app/routers/feedback.py
Endpunkt für User-Feedback (WP-04c). DESCRIPTION: Endpunkt für explizites User-Feedback (WP-04c).
VERSION: 0.1.0
STATUS: Active
DEPENDENCIES: app.models.dto, app.services.feedback_service
LAST_ANALYSIS: 2025-12-15
""" """
from fastapi import APIRouter, HTTPException from fastapi import APIRouter, HTTPException
from app.models.dto import FeedbackRequest from app.models.dto import FeedbackRequest

View File

@ -1,21 +1,10 @@
""" """
app/routers/graph.py Graph-Endpunkte (WP-04) FILE: app/routers/graph.py
DESCRIPTION: Liefert Graph-Daten (Knoten/Kanten) für UI-Visualisierungen basierend auf einer Seed-ID. (WP4)
Zweck: VERSION: 0.1.0
Liefert die Nachbarschaft einer Note/ID als JSON-Graph (Nodes/Edges/Stats). STATUS: Active
Kompatibilität: DEPENDENCIES: qdrant_client, app.models.dto, app.core.graph_adapter, app.config
Python 3.12+, FastAPI 0.110+, qdrant-client 1.x LAST_ANALYSIS: 2025-12-15
Version:
0.1.0 (Erstanlage)
Stand:
2025-10-07
Bezug:
- app/core/graph_adapter.py
- app/models/dto.py
Nutzung:
app.include_router(graph.router, prefix="/graph", tags=["graph"])
Änderungsverlauf:
0.1.0 (2025-10-07) Erstanlage.
""" """
from __future__ import annotations from __future__ import annotations

View File

@ -1,8 +1,12 @@
""" """
app/routers/ingest.py FILE: app/routers/ingest.py
API-Endpunkte für WP-11 (Discovery & Persistence). DESCRIPTION: Endpunkte für WP-11. Nimmt Markdown entgegen, steuert Ingestion und Discovery (Link-Vorschläge).
Delegiert an Services. VERSION: 0.6.0
STATUS: Active
DEPENDENCIES: app.core.ingestion, app.services.discovery, fastapi, pydantic
LAST_ANALYSIS: 2025-12-15
""" """
import os import os
import time import time
import logging import logging

View File

@ -1,23 +1,12 @@
""" """
app/routers/query.py Query-Endpunkte (WP-04) FILE: app/routers/query.py
DESCRIPTION: Klassische Such-Endpunkte (Semantic & Hybrid). Initiiert asynchrones Feedback-Logging und ruft den richtigen Retriever Modus auf
VERSION: 0.2.0
STATUS: Active
DEPENDENCIES: app.models.dto, app.core.retriever, app.services.feedback_service
LAST_ANALYSIS: 2025-12-15
"""
Zweck:
Stellt POST /query bereit und ruft den passenden Retriever-Modus auf.
Kompatibilität:
Python 3.12+, FastAPI 0.110+
Version:
0.1.0 (Erstanlage)
Stand:
2025-10-07
Bezug:
- app/core/retriever.py
- app/models/dto.py
Nutzung:
app.include_router(query.router, prefix="/query", tags=["query"])
Änderungsverlauf:
0.2.0 (2025-12-07) - Update für WP04c Feedback
0.1.0 (2025-10-07) Erstanlage.
"""
from __future__ import annotations from __future__ import annotations
from fastapi import APIRouter, HTTPException, BackgroundTasks from fastapi import APIRouter, HTTPException, BackgroundTasks
from app.models.dto import QueryRequest, QueryResponse from app.models.dto import QueryRequest, QueryResponse

View File

@ -1,21 +1,10 @@
""" """
app/routers/tools.py Tool-Definitionen für Ollama/n8n/MCP (read-only) FILE: app/routers/tools.py
DESCRIPTION: Liefert JSON-Schemas für die Integration als 'Tools' in Agents (Ollama/OpenAI). Read-Only.
Zweck: VERSION: 0.1.1
Liefert Funktions-Schemas (OpenAI-/Ollama-kompatibles Tool-JSON) für: STATUS: Active
- mindnet_query -> POST /query DEPENDENCIES: fastapi
- mindnet_subgraph -> GET /graph/{note_id} LAST_ANALYSIS: 2025-12-15
Kompatibilität:
Python 3.12+, FastAPI 0.110+
Version:
0.1.1 (query ODER query_vector möglich)
Stand:
2025-10-07
Nutzung:
app.include_router(tools.router, prefix="/tools", tags=["tools"])
Änderungsverlauf:
0.1.1 (2025-10-07) mindnet_query: oneOf(query, query_vector).
0.1.0 (2025-10-07) Erstanlage.
""" """
from __future__ import annotations from __future__ import annotations

View File

@ -1,12 +1,11 @@
""" """
app/services/discovery.py FILE: app/services/discovery.py
Service für Link-Vorschläge und Knowledge-Discovery (WP-11). DESCRIPTION: Service für WP-11. Analysiert Texte, findet Entitäten und schlägt typisierte Verbindungen vor ("Matrix-Logic").
VERSION: 0.6.0
Features: STATUS: Active
- Sliding Window Analyse für lange Texte. DEPENDENCIES: app.core.qdrant, app.models.dto, app.core.retriever
- Footer-Scan für Projekt-Referenzen. EXTERNAL_CONFIG: config/types.yaml
- 'Matrix-Logic' für intelligente Kanten-Typen (Experience -> Value = based_on). LAST_ANALYSIS: 2025-12-15
- Async & Nomic-Embeddings kompatibel.
""" """
import logging import logging
import asyncio import asyncio

View File

@ -1,12 +1,10 @@
""" """
app/services/embeddings_client.py TextEmbedding Service FILE: app/services/embeddings_client.py
DESCRIPTION: Unified Embedding Client. Nutzt Ollama API (HTTP). Ersetzt lokale sentence-transformers.
Zweck: VERSION: 2.5.0
Einheitlicher Client für Embeddings via Ollama (Nomic). STATUS: Active
Stellt sicher, dass sowohl Async (Ingestion) als auch Sync (Retriever) DEPENDENCIES: httpx, requests, app.config
denselben Vektorraum (768 Dim) nutzen. LAST_ANALYSIS: 2025-12-15
Version: 2.5.0 (Unified Ollama)
""" """
from __future__ import annotations from __future__ import annotations
import os import os

View File

@ -1,9 +1,10 @@
""" """
app/services/feedback_service.py FILE: app/services/feedback_service.py
Service zum Loggen von Suchanfragen und Feedback (WP-04c). DESCRIPTION: Schreibt Search- und Feedback-Logs in JSONL-Dateien.
Speichert Daten als JSONL für späteres Self-Tuning (WP-08). VERSION: 1.1
STATUS: Active
Version: 1.1 (Chat-Support) DEPENDENCIES: app.models.dto
LAST_ANALYSIS: 2025-12-15
""" """
import json import json
import os import os

View File

@ -1,6 +1,11 @@
""" """
app/services/llm_service.py LLM Client FILE: app/services/llm_service.py
Version: 2.8.0 (Configurable Concurrency Limit) DESCRIPTION: Asynchroner Client für Ollama. Verwaltet Prompts und Background-Last (Semaphore).
VERSION: 2.8.0
STATUS: Active
DEPENDENCIES: httpx, yaml, asyncio, app.config
EXTERNAL_CONFIG: config/prompts.yaml
LAST_ANALYSIS: 2025-12-15
""" """
import httpx import httpx

View File

@ -1,6 +1,10 @@
""" """
app/services/semantic_analyzer.py Edge Validation & Filtering FILE: app/services/semantic_analyzer.py
Version: 2.0 (Update: Background Priority for Batch Jobs) DESCRIPTION: KI-gestützte Kanten-Validierung. Nutzt LLM (Background-Priority), um Kanten präzise einem Chunk zuzuordnen.
VERSION: 2.0.0
STATUS: Active
DEPENDENCIES: app.services.llm_service, json, logging
LAST_ANALYSIS: 2025-12-15
""" """
import json import json

View File

@ -9,145 +9,200 @@ context: "Umfassender Guide für Entwickler: Architektur, Modul-Interna (Deep Di
# Mindnet Developer Guide & Workflow # Mindnet Developer Guide & Workflow
**Quellen:** `developer_guide.md`, `dev_workflow.md` **Quellen:** `developer_guide.md`, `dev_workflow.md`, `Architecture_Audit_v2.6`
Dieser Guide vereint das technische Verständnis der Module mit dem operativen Workflow zwischen Windows (Dev) und Linux (Runtime). Dieser Guide ist die zentrale technische Referenz für Mindnet v2.6. Er vereint das technische Verständnis der Module mit dem operativen Workflow zwischen Windows (Dev) und Linux (Runtime).
--- ---
## 1. Die physische Architektur ## 1. Einführung & Systemüberblick
### Was ist Mindnet?
Mindnet ist ein **Hybrides Knowledge Management System**, das klassische Notizen (Markdown) mit KI-gestützter Analyse verbindet. Es kombiniert **RAG** (Retrieval Augmented Generation) mit einer **Graphen-Datenbank** (Qdrant), um Wissen nicht nur semantisch zu finden, sondern auch strukturell zu vernetzen.
### Kern-Philosophie
1. **Filesystem First:** Die Wahrheit liegt immer auf der Festplatte (Markdown-Dateien). Die Datenbank ist ein abgeleiteter Index.
2. **Hybrid Retrieval:** Relevanz entsteht aus Textähnlichkeit (Semantik) + Graphen-Verbindungen (Edges) + Wichtigkeit (Centrality).
3. **Active Intelligence:** Das System wartet nicht nur auf Anfragen, sondern schlägt beim Schreiben proaktiv Verbindungen vor ("Matrix Logic").
4. **Local Privacy:** Alle KI-Berechnungen (Ollama) laufen lokal. Keine Cloud-Abhängigkeit für Inference.
---
## 2. Architektur
### 2.1 High-Level Übersicht
Das System folgt einer strikten Trennung zwischen Frontend (Streamlit) und Backend (FastAPI), wobei bestimmte Performance-Pfade (Graph-Visualisierung) optimiert wurden.
```mermaid
graph TD
User((User))
subgraph "Frontend Layer (Streamlit)"
UI[ui.py Router]
ViewChat[Chat View]
ViewGraph[Graph View]
ViewEditor[Editor View]
Logic[Callbacks & State]
end
subgraph "Backend Layer (FastAPI)"
API[main.py]
RouterChat[Chat / RAG]
RouterIngest[Ingest / Write]
CoreRet[Retriever Engine]
CoreIngest[Ingestion Pipeline]
end
subgraph "Infrastructure & Services"
LLM[Ollama (Phi3/Nomic)]
DB[(Qdrant Vector DB)]
FS[File System (.md)]
end
User <--> UI
UI --> API : REST (Chat, Save, Feedback)
UI -.-> DB : Direct Read (Graph Viz Performance)
API --> LLM : Embeddings & Completion
API --> DB : Read/Write
API --> FS : Read/Write (Source of Truth)
```
### 2.2 Datenfluss-Muster
1. **Ingestion (Write):**
`Markdown` -> `Parser` -> `Chunker` -> `SemanticAnalyzer (LLM)` -> `Embedder` -> `Qdrant (Points)`
2. **Retrieval (Read):**
`Query` -> `Embedding` -> `Hybrid Search (Vector + Graph)` -> `Re-Ranking` -> `LLM Context`
3. **Visualisierung (Graph):**
`UI` -> `GraphService` -> `Qdrant (Edges Collection)` -> `Cytoscape`
---
## 3. Physische Architektur
Mindnet läuft in einer verteilten Umgebung (Post-WP15 Setup). Mindnet läuft in einer verteilten Umgebung (Post-WP15 Setup).
* **Windows 11 (VS Code):** Hier schreibst du Code. **Nie** direkt auf `main` arbeiten! * **Windows 11 (VS Code):** Entwicklungsumgebung. **Nie** direkt auf `main` arbeiten!
* **Beelink (Runtime):** Der Server. Hier läuft die Software. Wir nutzen **Systemd-Services**: * **Beelink (Runtime):** Der Server hostet zwei Instanzen via Systemd:
* **PROD:** API (8001) + UI (8501). Ordner: `~/mindnet`. * **PROD:** API (Port 8001) + UI (Port 8501). Home: `~/mindnet`.
* **DEV:** API (8002) + UI (8502). Ordner: `~/mindnet_dev`. * **DEV:** API (Port 8002) + UI (Port 8502). Home: `~/mindnet_dev`.
* **Gitea:** Der "Safe" (Raspberry Pi). Speichert den Code und verwaltet Versionen. * **Gitea (Raspberry Pi):** Versionskontrolle ("Safe"). Speichert den Code.
--- ---
## 2. Projektstruktur & Referenz ## 4. Projektstruktur & Modul-Referenz (Deep Dive)
### 2.1 Verzeichnisbaum Das System ist modular aufgebaut. Hier ist die detaillierte Analyse aller Komponenten.
### 4.1 Verzeichnisbaum
```text ```text
mindnet/ mindnet/
├── app/ ├── app/
│ ├── core/ # Ingestion, Chunker, Qdrant Wrapper │ ├── core/ # Business Logic & Algorithms
│ ├── routers/ # FastAPI Endpoints │ ├── routers/ # API Interface (FastAPI)
│ ├── services/ # Ollama Client, Traffic Control │ ├── services/ # External Integrations (LLM, DB)
│ ├── models/ # Pydantic DTOs │ ├── models/ # Pydantic DTOs
│ └── frontend/ # Streamlit UI Module │ └── frontend/ # UI Logic (Streamlit)
├── config/ # YAML Configs (Single Source of Truth) ├── config/ # Configuration Files (YAML)
├── scripts/ # CLI Tools (Import, Diagnose, Reset) ├── scripts/ # CLI Tools (Ops & Maintenance)
├── tests/ # Pytest Suite & Smoke Scripts └── vault/ # Local Content Storage
└── vault/ # Lokaler Test-Content
``` ```
### 2.2 Vollständige Datei-Referenz (Auto-Scan) ### 4.2 Frontend Architecture (`app/frontend/`)
Eine Übersicht aller Skripte und Module im System. Das Frontend ist eine Streamlit-App, die sich wie eine Single-Page-Application (SPA) verhält.
| Datei/Pfad | Typ | Beschreibung | | Modul | Status | Verantwortung |
| :--- | :--- | :--- | | :--- | :--- | :--- |
| **Backend Core** | | | | **`ui.py`** | 🟢 Core | **Main Router.** Initialisiert Session-State und entscheidet anhand der Sidebar-Auswahl, welche View gerendert wird. |
| `app/main.py` | Skript | Bootstrap der FastAPI API. | | **`ui_config.py`** | 🟢 Config | **Constants.** Zentraler Ort für Farben (`GRAPH_COLORS`), API-URLs und Timeouts. Änderungen am Look & Feel passieren hier. |
| `app/config.py` | Config | Zentrale Konfiguration (Pydantic Settings). | | **`ui_chat.py`** | 🟢 View | **Chat UI.** Rendert Nachrichtenverlauf, Intent-Badges, Quellen-Expanders und Feedback-Buttons. |
| `app/core/ingestion.py` | Core Modul | Async Ingestion Service & Change Detection. | | **`ui_editor.py`** | 🟢 View | **Editor UI.** Markdown-Editor mit Live-Vorschau. Integriert "Intelligence" (KI-Link-Vorschläge). |
| `app/core/chunker.py` | Core Modul | Smart Chunker Orchestrator. | | **`ui_graph_cytoscape.py`**| 🟢 View | **Modern Graph.** Interaktiver Graph basierend auf Cytoscape.js (COSE Layout). |
| `app/core/retriever.py` | Core Modul | Hybrider Such-Algorithmus (Semantik + Graph). | | **`ui_graph.py`** | 🟡 Legacy | **Graph UI (Fallback).** Alte Implementierung mittels `streamlit-agraph`. |
| `app/core/ranking.py` | Core Modul | Kombiniertes Scoring (WP-04). | | **`ui_callbacks.py`** | 🟢 Logic | **State Controller.** Handhabt komplexe State-Übergänge (z.B. Graph -> Editor). |
| `app/core/graph_adapter.py` | Core Modul | Adjazenzaufbau & Subgraph-Expansion. | | **`ui_utils.py`** | 🟢 Logic | **Helper.** Enthält den **Healing Parser** (`parse_markdown_draft`), der defektes JSON/YAML von LLMs repariert. |
| `app/core/qdrant.py` | Core Modul | Qdrant Client Wrapper. | | **`ui_api.py`** | 🟢 Data | **API Client.** Wrapper für Backend REST-Calls. |
| `app/core/qdrant_points.py` | Core Modul | Robuste Point-Helper für Qdrant (Retry-Logik). | | **`ui_graph_service.py`** | 🟢 Data | **Performance Hack.** Greift direkt auf Qdrant zu (bypass API), um Graphen schnell zu laden. |
| `app/core/derive_edges.py` | Core Modul | Edge-Erzeugung aus Markdown. |
| `app/core/edges.py` | Core Modul | Datenstrukturen für Kanten. | #### Frontend Design Patterns (Wichtig!)
| `app/core/edges_writer.py` | Core Modul | Schreibt Kanten in die DB. |
| `app/core/note_payload.py` | Core Modul | Builder für Note-Metadaten. | 1. **Active Inspector Pattern (`ui_graph_cytoscape.py`)**
| `app/core/chunk_payload.py` | Core Modul | Builder für Chunk-Payloads. | Um Re-Renders im Graphen zu vermeiden, nutzen wir CSS-Klassen. Wird ein Knoten angeklickt, ändert sich nur die CSS-Klasse (`.inspected`), aber die Physik-Simulation startet nicht neu. Das sorgt für ein stabiles UI-Gefühl.
| `app/core/type_registry.py` | Core Modul | Logik zum Laden der `types.yaml`. |
| `app/core/schema_loader.py` | Core Modul | Lädt JSON-Schemas für Validierung. | 2. **Resurrection Pattern (`ui_editor.py`)**
| `app/core/env_vars.py` | Core Modul | Environment-Variablen Konstanten. | Streamlit neigt dazu, Eingaben bei Re-Runs zu "vergessen". Der Editor synchronisiert seinen Inhalt aggressiv in den `session_state`.
| **API Router** | | | * Logik: `if widget_key not in session_state: restore_from_data_key()`.
| `app/routers/chat.py` | API Router | RAG Endpunkt & Hybrid Router. | * Ergebnis: Texteingaben überleben Tab-Wechsel.
| `app/routers/query.py` | API Router | Query-Endpunkte (WP-04). |
| `app/routers/graph.py` | API Router | Graph-Endpunkte (WP-04). | 3. **Filesystem First (`ui_callbacks.py`)**
| `app/routers/ingest.py` | API Router | Ingestion-Trigger & Analyse. | Wenn man im Graphen auf "Bearbeiten" klickt:
| `app/routers/feedback.py` | API Router | Feedback-Endpunkt. | 1. Versucht das System, die **echte Datei** von der Festplatte zu lesen.
| `app/routers/tools.py` | API Router | Tool-Definitionen für Ollama/n8n/MCP. | 2. Nur wenn das fehlschlägt, wird der Text aus den Datenbank-Chunks rekonstruiert ("Stitching").
| `app/routers/admin.py` | API Router | Admin-/Monitoring-Endpunkte. | Dies verhindert, dass veraltete Datenbank-Stände die echten Dateien überschreiben.
---
### 4.3 Backend Architecture (`app/`)
Das Backend stellt die Logik via REST-API bereit.
| Modul | Typ | Verantwortung |
| :--- | :--- | :--- |
| **Core Engine** | | |
| `core/ingestion.py` | Engine | **Pipeline Controller.** Koordiniert den 13-Schritte-Import, Parsing, Hash-Check und DB-Upserts. |
| `core/retriever.py` | Engine | **Search Engine.** Berechnet Hybrid-Score: `(Semantic * W) + (Edge Bonus * 0.25) + (Centrality * 0.05)`. |
| `core/chunker.py` | Engine | **Segmentation.** Zerlegt Text intelligent. Orchestriert `SemanticAnalyzer` für Smart Edges. |
| `core/derive_edges.py`| Engine | **Link Extractor.** Findet Wikilinks, Callouts und Typed Relations im Text. |
| `core/qdrant_points.py`| Mapper | **Object Mapper.** Wandelt Payloads in Qdrant `PointStruct`s um. |
| `core/graph_adapter.py` | Algo | **Graph Logic.** Baut In-Memory Graphen für Re-Ranking und Pfad-Analysen. |
| **Router (API)** | | |
| `routers/chat.py` | Router | **Hybrid Router.** Entscheidet: RAG-Antwort vs. Interview-Modus. |
| `routers/ingest.py` | Router | **Write API.** Nimmt Markdown entgegen, steuert Ingestion und Discovery-Analyse. |
| `routers/query.py` | Router | **Search API.** Klassischer Hybrid-Retriever Endpunkt. |
| `routers/graph.py` | Router | **Viz API.** Liefert Knoten/Kanten für Frontend. |
| **Services** | | | | **Services** | | |
| `app/services/llm_service.py` | Service | LLM Client mit Traffic Control. | | `services/llm_service.py`| Service | **Traffic Control.** Async Client für Ollama. Nutzt **Semaphore**, um Hintergrund-Jobs (Import) zu drosseln. |
| `app/services/llm_ollama.py` | Service | Legacy: Ollama-Integration & Prompt-Bau. | | `services/discovery.py`| Service | **Intelligence.** "Matrix Logic" für Link-Vorschläge (WP-11). |
| `app/services/embeddings_client.py` | Service | Async Text→Embedding Service. | | `services/semantic_analyzer.py`| Service | **Filter.** KI-Validierung von Kanten im Hintergrund. |
| `app/services/semantic_analyzer.py` | Service | Smart Edge Validation & Filtering. | | `services/feedback_service.py`| Service | **Logging.** Schreibt Interaktions-Logs (JSONL). |
| `app/services/discovery.py` | Service | Backend Intelligence (Matrix-Logik). |
| `app/services/feedback_service.py` | Service | Schreibt JSONL-Logs. |
| **Frontend** | | |
| `app/frontend/ui.py` | Frontend | Entrypoint (Streamlit). |
| `app/frontend/ui_editor.py` | Frontend | Editor-View & Logic. |
| `app/frontend/ui_chat.py` | Frontend | Chat-View. |
| `app/frontend/ui_graph_cytoscape.py` | Frontend | Graph-Visualisierung (Modern). |
| `app/frontend/ui_graph.py` | Frontend | Graph-Visualisierung (Legacy). |
| `app/frontend/ui_graph_service.py` | Frontend | Datenaufbereitung für Graphen. |
| `app/frontend/ui_callbacks.py` | Frontend | Event-Handler. |
| `app/frontend/ui_api.py` | Frontend | Backend-Bridge. |
| `app/frontend/ui_utils.py` | Frontend | Helper (Healing Parser). |
| `app/frontend/ui_config.py` | Frontend | Konstanten (Farben, URLs). |
| **CLI & Scripts** | | |
| `scripts/import_markdown.py` | Skript | Haupt-Importer CLI. |
| `scripts/reset_qdrant.py` | Skript | Löscht Collections (`--mode wipe`). |
| `scripts/payload_dryrun.py` | Skript | Zeigt Payloads VOR dem Upsert. |
| `scripts/edges_dryrun.py` | Skript | Erzeugt Edges ohne DB-Write. |
| `scripts/edges_full_check.py` | Skript | Prüft Graph-Integrität. |
| `scripts/resolve_unresolved_references.py`| Skript | Löst Wikilinks nachträglich auf. |
| `scripts/audit_vault_vs_qdrant.py` | Skript | Konsistenz-Check File vs. DB. |
| `scripts/audit_edges_vs_expectations.py`| Skript | Prüft Kanten gegen Erwartungswert. |
| `scripts/setup_mindnet_collections.py` | Skript | Richtet Collections initial ein. |
| `scripts/export_markdown.py` | Skript | Exportiert Qdrant zurück zu Markdown. |
| `scripts/wp04_smoketest.py` | Skript | E2E-Schnelltest der WP-04 Endpunkte. |
| `scripts/health_check_mindnet.py` | Skript | System Health Check. |
| `scripts/report_hashes.py` | Skript | Übersicht bei Mehrfach-Hashes. |
| `scripts/make_test_vault.py` | Skript | Erzeugt minimalen Test-Vault. |
| `scripts/ollama_tool_runner.py` | Skript | Minimaler Tool-Caller für Ollama. |
--- ---
## 3. Core-Module im Detail (Architektur) ### 4.4 Scripts & Tooling (Die Admin-Toolbox)
Hier wird erklärt, *wie* die wichtigsten Komponenten unter der Haube arbeiten. Der Ordner `scripts/` enthält verifizierte Werkzeuge für den Betrieb.
### 3.1 Der Importer (`scripts.import_markdown`) | Skript | Status | Zweck | Wichtiges Argument |
Dies ist das komplexeste Modul. | :--- | :--- | :--- | :--- |
* **Orchestrierung:** Es ruft `app.core.chunker` für die Textzerlegung und `app.services.semantic_analyzer` für Smart Edges auf. | **`import_markdown.py`** | 🟢 Prod | **Master-Sync.** Der zentrale Importer. | `--apply`, `--purge-before-upsert` |
* **Idempotenz:** Der Importer kann beliebig oft laufen. Er nutzt deterministische IDs (UUIDv5) und überschreibt vorhandene Einträge konsistent. | **`reset_qdrant.py`** | ⚠️ Ops | **Wipe.** Löscht Collections für Rebuilds. | `--mode wipe`, `--yes` |
* **Robustheit:** In `ingestion.py` sind Mechanismen wie Change Detection (Hash-Vergleich) und Robust File I/O implementiert. | **`export_markdown.py`** | 🟢 Backup| **Backup.** Exportiert DB-Inhalt zurück zu MD. | -- |
| **`health_check_mindnet.py`**| 🟢 Ops | **Monitoring.** Prüft ob API/DB laufen. | (Exit Code 0/1) |
### 3.2 Der Hybrid Router (`app.routers.chat`) | **`payload_dryrun.py`** | 🟢 Test | **Audit.** Simuliert Import (Schema Check). | -- |
Hier liegt die Logik für Intent Detection (WP06) und Interview-Modus (WP07). | **`edges_full_check.py`** | 🟢 Test | **Integrity.** Prüft Graph-Logik. | -- |
* **Question Detection:** Prüft zuerst regelbasiert, ob der Input eine Frage ist (`?`, W-Wörter). Falls ja -> RAG. | **`resolve_unresolved.py`**| 🟡 Maint | **Repair.** Versucht, kaputte Links zu heilen. | -- |
* **Keyword Match:** Prüft Keywords aus `decision_engine.yaml` und `types.yaml`.
* **Priority:** Ruft `llm_service` mit `priority="realtime"` auf, um die Import-Warteschlange zu umgehen.
### 3.3 Der Retriever (`app.core.retriever`)
Hier passiert das Scoring (WP04a).
* **Hybrid Search:** Der Chat-Endpoint erzwingt `mode="hybrid"`.
* **Strategic Retrieval:** In `chat.py` wird der Retriever ggf. *zweimal* aufgerufen, wenn ein Intent (z.B. `DECISION`) eine Injection (`value`) erfordert.
### 3.4 Das Frontend (`app.frontend.ui`)
Eine Streamlit-App (WP10/19).
* **Resurrection Pattern:** Das UI nutzt ein spezielles State-Management (`st.session_state`), um Eingaben bei Tab-Wechseln (Chat <-> Editor) zu erhalten. Widgets synchronisieren sich via Callbacks.
* **Healing Parser:** Die Funktion `parse_markdown_draft` repariert defekte YAML-Frontmatter (z.B. fehlendes `---`) vom LLM automatisch.
### 3.5 Traffic Control (`app.services.llm_service`)
Neu in v2.6. Stellt sicher, dass Batch-Prozesse (Import) den Live-Chat nicht ausbremsen.
* **Methode:** `generate_raw_response(..., priority="background")` aktiviert eine Semaphore.
* **Limit:** Konfigurierbar über `MINDNET_LLM_BACKGROUND_LIMIT` (Default: 2).
--- ---
## 4. Lokales Setup (Development) ## 5. Maintenance & "Kill List"
Folgende Dateien wurden im Audit v2.6 als veraltet, redundant oder "Zombie-Code" identifiziert und sollten entfernt werden.
| Datei | Diagnose | Empfohlene Aktion |
| :--- | :--- | :--- |
| `app/embed_server.py` | **Zombie.** Alter Standalone-Server. | 🗑️ Löschen |
| `app/embeddings.py` | **Zombie.** Veraltete lokale Lib. | 🗑️ Löschen |
| `app/core/edges.py` | **Redundant.** Ersetzt durch `derive_edges.py`. | 🗑️ Löschen |
| `app/core/ranking.py` | **Redundant.** Logik in `retriever.py` integriert. | 🗑️ Löschen |
| `app/core/type_registry.py` | **Redundant.** Logik in `ingestion.py` integriert. | 🗑️ Löschen |
| `app/core/env_vars.py` | **Veraltet.** Ersetzt durch `config.py`. | 🗑️ Löschen |
| `app/routers/qdrant_router.py`| **Deprecated.** Keine Logik, nur CRUD. | 📂 Verschieben nach `scripts/archive/` |
---
## 6. Lokales Setup (Development)
**Voraussetzungen:** Python 3.10+, Docker, Ollama. **Voraussetzungen:** Python 3.10+, Docker, Ollama.
@ -170,16 +225,18 @@ ollama pull nomic-embed-text
**Konfiguration (`.env`):** **Konfiguration (`.env`):**
```ini ```ini
QDRANT_URL="http://localhost:6333" QDRANT_URL="http://localhost:6333"
MINDNET_OLLAMA_URL="http://localhost:11434"
MINDNET_LLM_MODEL="phi3:mini"
MINDNET_EMBEDDING_MODEL="nomic-embed-text"
COLLECTION_PREFIX="mindnet_dev" COLLECTION_PREFIX="mindnet_dev"
VECTOR_DIM=768 VECTOR_DIM=768
MINDNET_LLM_BACKGROUND_LIMIT=2 MINDNET_LLM_BACKGROUND_LIMIT=2
MINDNET_API_URL="http://localhost:8002" MINDNET_API_URL="http://localhost:8002"
MINDNET_LLM_TIMEOUT=300.0
``` ```
--- ---
## 5. Der Entwicklungs-Zyklus (Workflow) ## 7. Der Entwicklungs-Zyklus (Workflow)
### Phase 1: Windows (Code) ### Phase 1: Windows (Code)
1. **Basis aktualisieren:** `git checkout main && git pull`. 1. **Basis aktualisieren:** `git checkout main && git pull`.
@ -219,7 +276,7 @@ Wenn alles getestet ist:
--- ---
## 6. Erweiterungs-Guide: "Teach-the-AI" ## 8. Erweiterungs-Guide: "Teach-the-AI"
Mindnet lernt nicht durch Training (Fine-Tuning), sondern durch **Konfiguration** und **Vernetzung**. Mindnet lernt nicht durch Training (Fine-Tuning), sondern durch **Konfiguration** und **Vernetzung**.
@ -227,6 +284,7 @@ Mindnet lernt nicht durch Training (Fine-Tuning), sondern durch **Konfiguration*
1. **Physik (`config/types.yaml`):** 1. **Physik (`config/types.yaml`):**
```yaml ```yaml
risk: risk:
chunk_profile: sliding_short
retriever_weight: 0.90 # Sehr wichtig retriever_weight: 0.90 # Sehr wichtig
edge_defaults: ["blocks"] # Automatische Kante edge_defaults: ["blocks"] # Automatische Kante
detection_keywords: ["gefahr", "risiko"] detection_keywords: ["gefahr", "risiko"]
@ -238,21 +296,20 @@ Mindnet lernt nicht durch Training (Fine-Tuning), sondern durch **Konfiguration*
``` ```
*Ergebnis:* Wenn der Intent `DECISION` erkannt wird, sucht das System nun auch aktiv nach Risiken. *Ergebnis:* Wenn der Intent `DECISION` erkannt wird, sucht das System nun auch aktiv nach Risiken.
### Workflow B: Interview-Schema anpassen (WP07) ### Workflow B: Graph-Farben ändern
Wenn Mindnet neue Fragen stellen soll (z.B. "Budget" bei Projekten): 1. Öffne `app/frontend/ui_config.py`.
1. **Schema (`config/types.yaml`):** 2. Bearbeite das Dictionary `GRAPH_COLORS`.
```yaml
project: ```python
schema: GRAPH_COLORS = {
- "Titel" "project": "#FF4B4B",
- "Ziel" "risk": "#8B0000" # Neu
- "Budget (Neu)" }
``` ```
2. **Kein Code nötig:** Der `One-Shot Extractor` (Prompt Template) liest diese Liste dynamisch.
--- ---
## 7. Tests & Debugging ## 9. Tests & Debugging
**Unit Tests (Pytest):** **Unit Tests (Pytest):**
```bash ```bash
@ -280,7 +337,7 @@ python tests/test_feedback_smoke.py --url http://localhost:8002/query
--- ---
## 8. Troubleshooting & One-Liners ## 10. Troubleshooting & One-Liners
**DB komplett zurücksetzen (Vorsicht!):** **DB komplett zurücksetzen (Vorsicht!):**
```bash ```bash
@ -300,5 +357,9 @@ journalctl -u mindnet-ui-dev -f
``` ```
**"UnicodeDecodeError in .env":** **"UnicodeDecodeError in .env":**
* Ursache: Umlaute oder Sonderzeichen in der `.env`. * **Ursache:** Umlaute oder Sonderzeichen in der `.env`.
* Lösung: Datei bereinigen (nur ASCII) und sicherstellen, dass UTF-8 ohne BOM genutzt wird. * **Lösung:** Datei bereinigen (nur ASCII) und sicherstellen, dass UTF-8 ohne BOM genutzt wird.
**"Read timed out" im Frontend:**
* **Ursache:** Smart Edges brauchen länger als 60s.
* **Lösung:** `MINDNET_API_TIMEOUT=300.0` in `.env`.