"""app/core/retriever_config.py --------------------------------- Zentrale Konfiguration für den mindnet-Retriever (WP-04). Zweck: - Lädt config/retriever.yaml (falls vorhanden) oder nutzt sinnvolle Defaults. - Bietet einen gecachten Zugriff auf die Retriever-Config für andere Module (z. B. graph_adapter, retriever). Hinweis zur Weiterentwicklung (Selbstjustierung): - Die hier definierten Parameter sind so gewählt, dass sie später durch ein Feedback-/Learning-to-Rank-Modell überschrieben werden können, ohne die restliche Architektur anzupassen. """ from __future__ import annotations import os from dataclasses import dataclass from functools import lru_cache from pathlib import Path from typing import Dict try: import yaml # type: ignore except Exception: # pragma: no cover - Fallback, falls PyYAML nicht installiert ist. yaml = None # type: ignore @dataclass(frozen=True) class RetrieverConfig: semantic_scale: float edge_scale: float centrality_scale: float edge_weights: Dict[str, float] @lru_cache def get_retriever_config() -> RetrieverConfig: """Lädt die Retriever-Konfiguration (YAML + Defaults). Reihenfolge: 1. Defaults (sinnvoll gewählte Startwerte). 2. Optional: config/retriever.yaml bzw. Pfad aus ENV MINDNET_RETRIEVER_CONFIG überschreibt die Defaults. Die Funktion ist bewusst gecached, da sich die Konfiguration zur Laufzeit üblicherweise nicht ändert. Für dynamisches Nachladen könnte der Cache explizit geleert werden. """ # 1) Defaults – bewusst konservativ gewählt. semantic_scale = 1.0 edge_scale = 1.0 centrality_scale = 1.0 edge_weights: Dict[str, float] = { # Wissens-Kanten "depends_on": 1.0, "related_to": 0.7, "similar_to": 0.7, "references": 0.5, # Struktur-Kanten "belongs_to": 0.2, "next": 0.1, "prev": 0.1, # Sonstige / technische Kanten "backlink": 0.2, "references_at": 0.2, } # 2) Optional: YAML-Konfiguration laden cfg_path_env = os.getenv("MINDNET_RETRIEVER_CONFIG") if cfg_path_env: cfg_path = Path(cfg_path_env) else: # Project-Root = zwei Ebenen über app/core/ cfg_path = Path(__file__).resolve().parents[2] / "config" / "retriever.yaml" if yaml is not None and cfg_path.exists(): try: data = yaml.safe_load(cfg_path.read_text(encoding="utf-8")) or {} except Exception: data = {} retr = data.get("retriever") or {} # Skalenwerte überschreiben, falls angegeben try: semantic_scale = float(retr.get("semantic_scale", semantic_scale)) except (TypeError, ValueError): pass try: edge_scale = float(retr.get("edge_scale", edge_scale)) except (TypeError, ValueError): pass try: centrality_scale = float(retr.get("centrality_scale", centrality_scale)) except (TypeError, ValueError): pass # Edge-Gewichte je Kanten-Typ ew_cfg = retr.get("edge_weights") or {} if isinstance(ew_cfg, dict): for k, v in ew_cfg.items(): try: edge_weights[str(k)] = float(v) except (TypeError, ValueError): continue return RetrieverConfig( semantic_scale=semantic_scale, edge_scale=edge_scale, centrality_scale=centrality_scale, edge_weights=edge_weights, )