Fassadenauflösung unter app/core
All checks were successful
Deploy mindnet to llm-node / deploy (push) Successful in 4s

This commit is contained in:
Lars 2025-12-28 11:04:40 +01:00
parent 5225090490
commit e93bab6ea7
50 changed files with 66 additions and 164 deletions

View File

@ -1,10 +0,0 @@
"""
FILE: app/core/derive_edges.py
DESCRIPTION: Facade für das neue graph Package.
WP-14: Modularisierung abgeschlossen.
VERSION: 2.2.0
"""
from .graph.graph_derive_edges import build_edges_for_note
from .graph.graph_utils import PROVENANCE_PRIORITY
__all__ = ["build_edges_for_note", "PROVENANCE_PRIORITY"]

View File

@ -1,10 +0,0 @@
"""
FILE: app/core/graph_adapter.py
DESCRIPTION: Facade für das neue graph Package (Adapter-Teil).
WP-14: Modularisierung abgeschlossen.
VERSION: 0.5.0
"""
from .graph.graph_subgraph import Subgraph, expand
from .graph.graph_weights import EDGE_BASE_WEIGHTS
__all__ = ["Subgraph", "expand", "EDGE_BASE_WEIGHTS"]

View File

@ -38,7 +38,7 @@ from .ingestion_chunk_payload import make_chunk_payloads
# Fallback für Edges (Struktur-Verknüpfung)
try:
from app.core.derive_edges import build_edges_for_note
from app.core.graph.graph_derive_edges import build_edges_for_note
except ImportError:
def build_edges_for_note(*args, **kwargs): return []

View File

@ -1,22 +0,0 @@
"""
FILE: app/core/qdrant.py
DESCRIPTION: Proxy-Modul zur Aufrechterhaltung der Abwärtskompatibilität (WP-14).
Leitet alle Aufrufe an das neue database-Paket weiter.
STATUS: Proxy (Legacy-Support)
"""
from .database.qdrant import (
QdrantConfig,
get_client,
ensure_collections,
ensure_payload_indexes,
collection_names
)
# Re-Export für 100% Kompatibilität
__all__ = [
"QdrantConfig",
"get_client",
"ensure_collections",
"ensure_payload_indexes",
"collection_names",
]

View File

@ -1,24 +0,0 @@
"""
FILE: app/core/qdrant_points.py
DESCRIPTION: Proxy-Modul zur Aufrechterhaltung der Abwärtskompatibilität (WP-14).
Leitet Point-Operationen an das neue database-Paket weiter.
STATUS: Proxy (Legacy-Support)
"""
from .database.qdrant_points import (
points_for_note,
points_for_chunks,
points_for_edges,
upsert_batch,
get_edges_for_sources,
search_chunks_by_vector
)
# Re-Export für 100% Kompatibilität
__all__ = [
"points_for_note",
"points_for_chunks",
"points_for_edges",
"upsert_batch",
"get_edges_for_sources",
"search_chunks_by_vector"
]

View File

@ -25,10 +25,10 @@ import app.core.database.qdrant as qdr
import app.core.database.qdrant_points as qp
import app.services.embeddings_client as ec
import app.core.graph_adapter as ga
import app.core.graph.graph_subgraph as ga
# Mathematische Engine importieren (Bleibt vorerst in app.core)
from app.core.retriever_scoring import get_weights, compute_wp22_score
# Mathematische Engine importieren
from app.core.retrieval.retriever_scoring import get_weights, compute_wp22_score
logger = logging.getLogger(__name__)

View File

@ -1,14 +0,0 @@
"""
FILE: app/core/retriever.py
DESCRIPTION: Proxy-Modul zur Aufrechterhaltung der Abwärtskompatibilität (WP-14).
Leitet Retrieval-Anfragen an das neue retrieval-Paket weiter.
STATUS: Proxy (Legacy-Support)
"""
from .retrieval.retriever import (
Retriever,
hybrid_retrieve,
semantic_retrieve
)
# Re-Export für 100% Kompatibilität
__all__ = ["Retriever", "hybrid_retrieve", "semantic_retrieve"]

View File

@ -1,18 +0,0 @@
"""
FILE: app/core/retriever_scoring.py
DESCRIPTION: Proxy-Modul zur Aufrechterhaltung der Abwärtskompatibilität (WP-14).
Leitet Scoring-Berechnungen an das neue retrieval-Paket weiter.
STATUS: Proxy (Legacy-Support)
"""
from .retrieval.retriever_scoring import (
get_weights,
compute_wp22_score,
get_status_multiplier
)
# Re-Export für 100% Kompatibilität
__all__ = [
"get_weights",
"compute_wp22_score",
"get_status_multiplier"
]

View File

@ -21,7 +21,7 @@ from pathlib import Path
from app.config import get_settings
from app.models.dto import ChatRequest, ChatResponse, QueryRequest, QueryHit
from app.services.llm_service import LLMService
from app.core.retriever import Retriever
from app.core.retrieval.retriever import Retriever
from app.services.feedback_service import log_search
router = APIRouter()

View File

@ -12,7 +12,7 @@ from typing import List, Optional
from fastapi import APIRouter, Query
from qdrant_client import QdrantClient
from app.models.dto import GraphResponse, NodeDTO, EdgeDTO
from app.core.graph_adapter import expand
from app.core.graph.graph_subgraph import expand
from app.config import get_settings
router = APIRouter()

View File

@ -10,7 +10,7 @@ LAST_ANALYSIS: 2025-12-15
from __future__ import annotations
from fastapi import APIRouter, HTTPException, BackgroundTasks
from app.models.dto import QueryRequest, QueryResponse
from app.core.retriever import hybrid_retrieve, semantic_retrieve
from app.core.retrieval.retriever import hybrid_retrieve, semantic_retrieve
# NEU:
from app.services.feedback_service import log_search

View File

@ -13,9 +13,9 @@ import os
from typing import List, Dict, Any, Optional, Set
import yaml
from app.core.qdrant import QdrantConfig, get_client
from app.core.database.qdrant import QdrantConfig, get_client
from app.models.dto import QueryRequest
from app.core.retriever import hybrid_retrieve
from app.core.retrieval.retriever import hybrid_retrieve
logger = logging.getLogger(__name__)

View File

@ -64,7 +64,7 @@ import urllib.error
import urllib.request
from typing import Any, Dict, List
from app.core.qdrant import QdrantConfig, get_client, collection_names
from app.core.database.qdrant import QdrantConfig, get_client, collection_names
REQUIRED = {
"notes": ["note_id", "type", "title", "updated", "tags"],

View File

@ -61,9 +61,10 @@ import argparse, glob, json, os
from typing import List, Tuple
from app.core.parser import read_markdown # gibt je nach Implementierung ein Objekt ODER ein (fm, body)-Tuple
from app.core.qdrant import QdrantConfig, get_client, ensure_collections
from app.core.qdrant_points import points_for_edges, upsert_batch
from app.core.derive_edges import build_note_index, derive_wikilink_edges
from app.core.database.qdrant import QdrantConfig, get_client, ensure_collections
from app.core.database.qdrant_points import points_for_edges, upsert_batch
# TODO: build_note_index und derive_wikilink_edges müssen noch implementiert werden
# from app.core.graph.graph_derive_edges import build_note_index, derive_wikilink_edges
def _coerce_parsed(note_or_tuple):

View File

@ -71,7 +71,7 @@ from pathlib import Path
sys.path.insert(0, os.path.abspath("."))
from app.core.chunking import assemble_chunks
from app.core.derive_edges import build_edges_for_note
from app.core.graph.graph_derive_edges import build_edges_for_note
from app.core.parser import extract_wikilinks
from app.core.graph.graph_extractors import extract_typed_relations, extract_callout_relations

View File

@ -53,7 +53,7 @@ v1.0.0: Initial Release
"""
from __future__ import annotations
import argparse, os, json
from app.core.qdrant import QdrantConfig, get_client
from app.core.database.qdrant import QdrantConfig, get_client
def count_points(client, collection: str) -> int:
try:

View File

@ -60,7 +60,7 @@ import urllib.request
import urllib.error
from typing import Any, Dict
from app.core.qdrant import QdrantConfig, get_client, collection_names
from app.core.database.qdrant import QdrantConfig, get_client, collection_names
def _safe_model_dump(obj: Any) -> Dict[str, Any]:

View File

@ -76,7 +76,7 @@ from pathlib import Path
from typing import Dict, List, Optional
from app.core.parser import read_markdown, normalize_frontmatter
from app.core.derive_edges import build_edges_for_note
from app.core.graph.graph_derive_edges import build_edges_for_note
def _iter_markdown(vault: str):
for p in Path(vault).rglob("*.md"):

View File

@ -67,7 +67,7 @@ import json
from collections import Counter, defaultdict
from typing import Dict, Any, List, Tuple
from app.core.qdrant import QdrantConfig, get_client
from app.core.database.qdrant import QdrantConfig, get_client
from qdrant_client.http import models as rest

View File

@ -80,8 +80,7 @@ from typing import Dict, List, Optional, Tuple, Any
import yaml
from qdrant_client.http import models as rest
from app.core.qdrant import QdrantConfig, get_client
from app.core.qdrant import ensure_collections # safety
from app.core.database.qdrant import QdrantConfig, get_client, ensure_collections
# ---------------------------------------------------------------------
# Helpers

View File

@ -77,7 +77,7 @@ from qdrant_client import QdrantClient
from qdrant_client.http import models as rest
from app.core.parser import read_markdown, normalize_frontmatter, validate_required_frontmatter # :contentReference[oaicite:5]{index=5}
from app.core.qdrant import QdrantConfig, get_client, collection_names # :contentReference[oaicite:6]{index=6}
from app.core.database.qdrant import QdrantConfig, get_client, collection_names # :contentReference[oaicite:6]{index=6}
def iter_note_ids_from_vault(vault_root: str) -> Set[str]:
"""Liest alle Markdown-Dateien im Vault und sammelt valide Frontmatter-IDs."""

View File

@ -73,7 +73,7 @@ from app.core.parser import read_markdown, normalize_frontmatter, validate_requi
from app.core.chunking import assemble_chunks
from app.core.ingestion.ingestion_note_payload import make_note_payload
from app.core.ingestion.ingestion_chunk_payload import make_chunk_payloads
from app.core.derive_edges import build_edges_for_note
from app.core.graph.graph_derive_edges import build_edges_for_note
async def process_file(path: str, root: str, args):
"""Verarbeitet eine einzelne Datei asynchron."""

View File

@ -85,7 +85,7 @@ from typing import Dict, List, Set, Tuple
from qdrant_client import QdrantClient
from qdrant_client.http import models as rest
from app.core.qdrant import QdrantConfig, get_client, collection_names
from app.core.database.qdrant import QdrantConfig, get_client, collection_names
from app.core.parser import read_markdown, normalize_frontmatter

View File

@ -63,7 +63,7 @@ import os
from typing import List, Dict, Any
from qdrant_client.http import models as rest
from app.core.qdrant import QdrantConfig, get_client
from app.core.database.qdrant import QdrantConfig, get_client
def collections(prefix: str):
return f"{prefix}_notes", f"{prefix}_chunks", f"{prefix}_edges"

View File

@ -83,7 +83,7 @@ from dotenv import load_dotenv
from qdrant_client import QdrantClient
from qdrant_client.http import models as rest
from app.core.qdrant import (
from app.core.database.qdrant import (
QdrantConfig,
get_client,
ensure_collections,

View File

@ -70,8 +70,8 @@ import uuid
from typing import List, Dict, Any, Iterable
from qdrant_client import models
from app.core.qdrant import QdrantConfig, get_client
from app.core.qdrant_points import points_for_edges
from app.core.database.qdrant import QdrantConfig, get_client
from app.core.database.qdrant_points import points_for_edges
# Logging Setup
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")

View File

@ -67,7 +67,7 @@ from typing import Dict, List, Tuple, Optional
from qdrant_client.http import models as rest
from app.core.qdrant import QdrantConfig, get_client, collection_names
from app.core.database.qdrant import QdrantConfig, get_client, collection_names
def _chunk_sort_key(p: Dict, pid: str) -> Tuple[int,int,str]:
# Primär: payload.chunk_index, sekundär: Nummer am Ende der ID (#cNN oder #NN), sonst 0

View File

@ -23,7 +23,7 @@ import urllib.error
import urllib.request
from typing import Any, Dict, List
from app.core.qdrant import QdrantConfig, get_client, collection_names
from app.core.database.qdrant import QdrantConfig, get_client, collection_names
REQUIRED = {
"notes": ["note_id", "type", "title", "updated", "tags"],

View File

@ -9,7 +9,7 @@ if PROJECT_ROOT not in sys.path:
sys.path.insert(0, PROJECT_ROOT)
from qdrant_client.http import models as rest
from app.core.qdrant import QdrantConfig, get_client
from app.core.database.qdrant import QdrantConfig, get_client
def scroll_all(c, col, flt=None):
out, nextp = [], None

View File

@ -18,7 +18,7 @@ PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
if PROJECT_ROOT not in sys.path:
sys.path.insert(0, PROJECT_ROOT)
from app.core.qdrant import QdrantConfig, get_client
from app.core.database.qdrant import QdrantConfig, get_client
from qdrant_client.http import models as rest
def collections(prefix: str) -> Tuple[str, str, str]:

View File

@ -18,7 +18,7 @@ PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
if PROJECT_ROOT not in sys.path:
sys.path.insert(0, PROJECT_ROOT)
from app.core.qdrant import QdrantConfig, get_client
from app.core.database.qdrant import QdrantConfig, get_client
from qdrant_client.http import models as rest
def collections(prefix: str) -> Tuple[str, str, str]:

View File

@ -37,7 +37,7 @@ if PROJECT_ROOT not in sys.path:
from qdrant_client.http import models as rest # type: ignore
from app.core.qdrant import QdrantConfig, get_client, collection_names
from app.core.database.qdrant import QdrantConfig, get_client, collection_names
def fetch_edges_for_note(note_id: str, prefix: str | None, limit: int = 512) -> List[dict]:

View File

@ -10,7 +10,7 @@ WICHTIG: Einige Qdrant-Versionen liefern payload_schema nur, wenn
from __future__ import annotations
import argparse, json
from qdrant_client.http import models as rest
from app.core.qdrant import QdrantConfig, get_client, collection_names
from app.core.database.qdrant import QdrantConfig, get_client, collection_names
def compact_schema(ps: dict | None) -> dict:
if not isinstance(ps, dict):

View File

@ -33,8 +33,8 @@ PROJECT_ROOT = os.path.dirname(THIS_DIR)
if PROJECT_ROOT not in sys.path:
sys.path.insert(0, PROJECT_ROOT)
from app.core.qdrant import QdrantConfig, get_client # type: ignore
import app.core.graph_adapter as ga # type: ignore
from app.core.database.qdrant import QdrantConfig, get_client # type: ignore
import app.core.graph.graph_subgraph as ga # type: ignore
def build_subgraph_for_note(

View File

@ -14,7 +14,7 @@ import urllib.request
import urllib.error
from typing import Any, Dict
from app.core.qdrant import QdrantConfig, get_client, ensure_payload_indexes, collection_names
from app.core.database.qdrant import QdrantConfig, get_client, ensure_payload_indexes, collection_names
def _safe_model_dump(obj: Any) -> Dict[str, Any]:

View File

@ -17,7 +17,7 @@ from app.core.parser import read_markdown, normalize_frontmatter, validate_requi
from app.core.chunker import assemble_chunks
from app.core.chunk_payload import make_chunk_payloads
try:
from app.core.derive_edges import build_edges_for_note
from app.core.graph.graph_derive_edges import build_edges_for_note
except Exception:
from app.core.edges import build_edges_for_note # type: ignore

View File

@ -14,7 +14,7 @@ import argparse, json, os, sys
from typing import Dict, Any, List, Tuple
from qdrant_client.http import models as rest
from app.core.qdrant import QdrantConfig, get_client
from app.core.database.qdrant import QdrantConfig, get_client
def collections(prefix: str) -> Tuple[str, str, str]:
return f"{prefix}_notes", f"{prefix}_chunks", f"{prefix}_edges"

View File

@ -14,7 +14,7 @@ from unittest.mock import MagicMock, patch, AsyncMock
import app.routers.chat
from app.models.dto import ChatRequest, QueryHit, QueryRequest
from app.services.edge_registry import EdgeRegistry
from app.core.retriever import _compute_total_score, _get_status_multiplier
from app.core.retrieval.retriever_scoring import compute_wp22_score, get_status_multiplier
from app.routers.chat import _classify_intent, get_decision_strategy, chat_endpoint
class TestWP22Integration(unittest.IsolatedAsyncioTestCase):
@ -93,19 +93,19 @@ class TestWP22Integration(unittest.IsolatedAsyncioTestCase):
def test_scoring_math(self):
print("\n🔵 TEST 2: Scoring Math (Lifecycle)")
with patch("app.core.retriever._get_scoring_weights", return_value=(1.0, 1.0, 0.0)):
with patch("app.core.retrieval.retriever_scoring.get_weights", return_value=(1.0, 1.0, 0.0)):
# Stable (1.2)
self.assertEqual(_get_status_multiplier({"status": "stable"}), 1.2)
self.assertEqual(get_status_multiplier({"status": "stable"}), 1.2)
# Draft (0.5)
self.assertEqual(_get_status_multiplier({"status": "draft"}), 0.5)
self.assertEqual(get_status_multiplier({"status": "draft"}), 0.5)
# Scoring Formel Test: BaseScore * (1 + ConfigWeight + DynamicBoost)
# BaseScore = 0.5 (sem) * 1.2 (stable) = 0.6
# ConfigWeight = 1.0 (neutral) - 1.0 = 0.0
# DynamicBoost = (1.0 * 0.5) = 0.5
# Total = 0.6 * (1 + 0 + 0.5) = 0.9
total, _, _ = _compute_total_score(0.5, {"status": "stable", "retriever_weight": 1.0}, edge_bonus_raw=0.5)
self.assertAlmostEqual(total, 0.9)
result = compute_wp22_score(0.5, {"status": "stable", "retriever_weight": 1.0}, edge_bonus_raw=0.5)
self.assertAlmostEqual(result["total"], 0.9)
print("✅ Scoring OK.")
async def test_router_intent(self):

View File

@ -16,7 +16,7 @@ import json
from collections import Counter, defaultdict
from typing import Dict, Any, List, Tuple
from app.core.qdrant import QdrantConfig, get_client
from app.core.database.qdrant import QdrantConfig, get_client
def _scroll_all(client, collection: str):

View File

@ -8,7 +8,7 @@ Zeigt, ob typenbasierte edge_defaults-Relationen (z. B. depends_on/related_to) a
from __future__ import annotations
from collections import Counter
import json
from app.core.qdrant import QdrantConfig, get_client
from app.core.database.qdrant import QdrantConfig, get_client
def main():
cfg = QdrantConfig.from_env()

View File

@ -7,7 +7,7 @@ import os
from collections import Counter, defaultdict
from qdrant_client.http import models as rest
from app.core.qdrant import QdrantConfig, get_client
from app.core.database.qdrant import QdrantConfig, get_client
def _rel(pl: dict) -> str:

View File

@ -13,7 +13,7 @@ import argparse, json
from typing import Dict, Any, List, Tuple
from qdrant_client.http import models as rest
from app.core.qdrant import QdrantConfig, get_client
from app.core.database.qdrant import QdrantConfig, get_client
KINDS = ["belongs_to", "next", "prev", "references", "backlink"]

View File

@ -1,6 +1,6 @@
from fastapi.testclient import TestClient
from app.main import create_app
import app.core.graph_adapter as ga
import app.core.graph.graph_subgraph as ga
def _fake_get_edges_for_sources(client, prefix, source_ids, edge_types=None, limit=2048):
note_id = source_ids[0]

View File

@ -1,8 +1,8 @@
from fastapi.testclient import TestClient
from app.main import create_app
import app.services.embeddings_client as ec
import app.core.qdrant_points as qp
import app.core.graph_adapter as ga
import app.core.database.qdrant_points as qp
import app.core.graph.graph_subgraph as ga
def _fake_embed_text(text: str):
# Liefert stabilen 384-d Vektor ohne echtes Modell

View File

@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from app.main import create_app
import app.core.qdrant_points as qp
import app.core.graph_adapter as ga
import app.core.database.qdrant_points as qp
import app.core.graph.graph_subgraph as ga
def _fake_search_chunks_by_vector(client, prefix, vector, top=10, filters=None):
return [

View File

@ -1,7 +1,7 @@
from app.core import retriever as r
from app.core.retrieval import retriever as r
from app.models.dto import QueryRequest
import app.core.qdrant as qdr
import app.core.qdrant_points as qp
import app.core.database.qdrant as qdr
import app.core.database.qdrant_points as qp
import app.services.embeddings_client as ec

View File

@ -1,8 +1,8 @@
from app.core import retriever as r
from app.core.retrieval import retriever as r
from app.models.dto import QueryRequest
import app.core.qdrant as qdr
import app.core.qdrant_points as qp
import app.core.graph_adapter as ga
import app.core.database.qdrant as qdr
import app.core.database.qdrant_points as qp
import app.core.graph.graph_subgraph as ga
import app.services.embeddings_client as ec

View File

@ -1,7 +1,7 @@
from app.core import retriever as r
from app.core.retrieval import retriever as r
from app.models.dto import QueryRequest
import app.core.qdrant as qdr
import app.core.qdrant_points as qp
import app.core.database.qdrant as qdr
import app.core.database.qdrant_points as qp
import app.services.embeddings_client as ec

View File

@ -14,7 +14,7 @@ sys.path.insert(0, str(ROOT_DIR))
# Import der Kernkomponenten
from app.core import chunker
from app.core import derive_edges
from app.core.graph import graph_derive_edges as derive_edges
from app.services.semantic_analyzer import SemanticAnalyzer

View File

@ -39,7 +39,7 @@ if PROJECT_ROOT not in sys.path:
import yaml
from qdrant_client.http import models as rest
from app.core.qdrant import QdrantConfig, get_client
from app.core.database.qdrant import QdrantConfig, get_client
# --------------------------- Helpers ---------------------------