2025-12-27 10:25:35 +01:00
|
|
|
|
"""
|
|
|
|
|
|
FILE: app/core/ingestion/ingestion_validation.py
|
|
|
|
|
|
DESCRIPTION: WP-15b semantische Validierung von Kanten gegen den LocalBatchCache.
|
2026-01-02 20:43:31 +01:00
|
|
|
|
WP-25b: Umstellung auf Lazy-Prompt-Orchestration (prompt_key + variables).
|
|
|
|
|
|
VERSION: 2.14.0 (WP-25b: Lazy Prompt Integration)
|
2026-01-02 08:57:29 +01:00
|
|
|
|
STATUS: Active
|
|
|
|
|
|
FIX:
|
2026-01-02 20:43:31 +01:00
|
|
|
|
- WP-25b: Entfernung manueller Prompt-Formatierung zur Unterstützung modell-spezifischer Prompts.
|
|
|
|
|
|
- WP-25b: Umstellung auf generate_raw_response mit prompt_key="edge_validation".
|
|
|
|
|
|
- WP-25a: Voller Erhalt der MoE-Profilsteuerung und Fallback-Kaskade via LLMService.
|
2025-12-27 10:25:35 +01:00
|
|
|
|
"""
|
|
|
|
|
|
import logging
|
2026-01-02 08:57:29 +01:00
|
|
|
|
from typing import Dict, Any, Optional
|
2025-12-27 10:25:35 +01:00
|
|
|
|
from app.core.parser import NoteContext
|
|
|
|
|
|
|
2025-12-27 19:47:23 +01:00
|
|
|
|
# ENTSCHEIDENDER FIX: Import der neutralen Bereinigungs-Logik zur Vermeidung von Circular Imports
|
|
|
|
|
|
from app.core.registry import clean_llm_text
|
|
|
|
|
|
|
2025-12-27 10:25:35 +01:00
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
async def validate_edge_candidate(
|
|
|
|
|
|
chunk_text: str,
|
|
|
|
|
|
edge: Dict,
|
|
|
|
|
|
batch_cache: Dict[str, NoteContext],
|
|
|
|
|
|
llm_service: Any,
|
2026-01-02 08:57:29 +01:00
|
|
|
|
provider: Optional[str] = None,
|
|
|
|
|
|
profile_name: str = "ingest_validator"
|
2025-12-27 10:25:35 +01:00
|
|
|
|
) -> bool:
|
2025-12-27 19:47:23 +01:00
|
|
|
|
"""
|
2026-01-02 20:43:31 +01:00
|
|
|
|
WP-15b/25b: Validiert einen Kandidaten semantisch gegen das Ziel im Cache.
|
|
|
|
|
|
Nutzt Lazy-Prompt-Loading zur Unterstützung modell-spezifischer Validierungs-Templates.
|
2025-12-27 19:47:23 +01:00
|
|
|
|
"""
|
2025-12-27 10:25:35 +01:00
|
|
|
|
target_id = edge.get("to")
|
|
|
|
|
|
target_ctx = batch_cache.get(target_id)
|
|
|
|
|
|
|
|
|
|
|
|
# Robust Lookup Fix (v2.12.2): Support für Anker
|
|
|
|
|
|
if not target_ctx and "#" in target_id:
|
|
|
|
|
|
base_id = target_id.split("#")[0]
|
|
|
|
|
|
target_ctx = batch_cache.get(base_id)
|
|
|
|
|
|
|
|
|
|
|
|
# Sicherheits-Fallback (Hard-Link Integrity)
|
2026-01-02 08:57:29 +01:00
|
|
|
|
# Explizite Wikilinks oder Callouts werden nicht durch das LLM verifiziert.
|
2025-12-27 10:25:35 +01:00
|
|
|
|
if not target_ctx:
|
|
|
|
|
|
logger.info(f"ℹ️ [VALIDATION SKIP] No context for '{target_id}' - allowing link.")
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
2026-01-02 08:57:29 +01:00
|
|
|
|
logger.info(f"⚖️ [VALIDATING] Relation '{edge.get('kind')}' -> '{target_id}' (Profile: {profile_name})...")
|
2025-12-27 10:25:35 +01:00
|
|
|
|
|
2026-01-02 20:43:31 +01:00
|
|
|
|
# WP-25b: Lazy-Prompt Aufruf.
|
|
|
|
|
|
# Wir übergeben keine formatierte Nachricht mehr, sondern Key und Daten-Dict.
|
|
|
|
|
|
# Das manuelle 'template = llm_service.get_prompt(...)' entfällt hier.
|
2026-01-02 08:57:29 +01:00
|
|
|
|
raw_response = await llm_service.generate_raw_response(
|
2026-01-02 20:43:31 +01:00
|
|
|
|
prompt_key="edge_validation",
|
|
|
|
|
|
variables={
|
|
|
|
|
|
"chunk_text": chunk_text[:1500],
|
|
|
|
|
|
"target_title": target_ctx.title,
|
|
|
|
|
|
"target_summary": target_ctx.summary,
|
|
|
|
|
|
"edge_kind": edge.get("kind", "related_to")
|
|
|
|
|
|
},
|
2026-01-02 08:57:29 +01:00
|
|
|
|
priority="background",
|
|
|
|
|
|
profile_name=profile_name
|
|
|
|
|
|
)
|
2025-12-27 19:47:23 +01:00
|
|
|
|
|
2026-01-02 20:43:31 +01:00
|
|
|
|
# WP-14 Fix: Bereinigung zur Sicherstellung der Interpretierbarkeit
|
2025-12-27 19:47:23 +01:00
|
|
|
|
response = clean_llm_text(raw_response)
|
|
|
|
|
|
|
|
|
|
|
|
# Semantische Prüfung des Ergebnisses
|
2025-12-27 10:25:35 +01:00
|
|
|
|
is_valid = "YES" in response.upper()
|
|
|
|
|
|
|
|
|
|
|
|
if is_valid:
|
|
|
|
|
|
logger.info(f"✅ [VALIDATED] Relation to '{target_id}' confirmed.")
|
|
|
|
|
|
else:
|
|
|
|
|
|
logger.info(f"🚫 [REJECTED] Relation to '{target_id}' irrelevant for this chunk.")
|
|
|
|
|
|
return is_valid
|
2026-01-02 20:43:31 +01:00
|
|
|
|
|
2025-12-27 10:25:35 +01:00
|
|
|
|
except Exception as e:
|
2026-01-02 08:57:29 +01:00
|
|
|
|
logger.warning(f"⚠️ Validation error for {target_id} using {profile_name}: {e}")
|
2025-12-27 19:47:23 +01:00
|
|
|
|
# Im Zweifel (Timeout/Fehler) erlauben wir die Kante, um Datenverlust zu vermeiden
|
2025-12-27 10:25:35 +01:00
|
|
|
|
return True
|