mindnet/app/routers/ingest.py
2025-12-11 11:35:27 +01:00

130 lines
4.1 KiB
Python

"""
app/routers/ingest.py - DEBUG VERSION
"""
import os
import time
import logging
from fastapi import APIRouter, HTTPException
from pydantic import BaseModel
from typing import Optional, List, Dict, Any
from app.core.ingestion import IngestionService
from app.core.retriever import Retriever
from app.models.dto import QueryRequest
logger = logging.getLogger(__name__)
router = APIRouter()
# --- DTOs ---
class AnalyzeRequest(BaseModel):
text: str
type: str = "concept"
class SaveRequest(BaseModel):
markdown_content: str
filename: Optional[str] = None
folder: str = "00_Inbox"
class SaveResponse(BaseModel):
status: str
file_path: str
note_id: str
stats: Dict[str, Any]
# --- Endpoints ---
@router.post("/analyze")
async def analyze_draft(req: AnalyzeRequest):
"""
WP-11 Intelligence: Liefert Link-Vorschläge.
DEBUG MODE: Threshold gesenkt, Logging erhöht.
"""
try:
retriever = Retriever()
suggestions = []
query_text = req.text[:400]
logger.info(f"ANALYZING TEXT: '{query_text}' (Type: {req.type})")
if not query_text.strip():
return {"suggestions": []}
# Wir suchen
hits_result = await retriever.search(QueryRequest(query=query_text, top_k=5, mode="hybrid"))
logger.info(f"RETRIEVER FOUND: {len(hits_result.results)} raw hits")
seen_titles = set()
for hit in hits_result.results:
# Titel holen
title = hit.payload.get("title") or hit.payload.get("note_id") or hit.node_id
# Logging für jeden Treffer
logger.info(f" -> CHECK HIT: {title} | Score: {hit.total_score:.4f}")
if not title or title in seen_titles:
continue
seen_titles.add(title)
# Edge Logic
edge_kind = "related_to"
if req.type == "project": edge_kind = "depends_on"
if req.type == "decision": edge_kind = "references"
# --- ÄNDERUNG: THRESHOLD GESENKT ---
# War vorher 0.65. Jetzt 0.3 für Tests.
if hit.total_score > 0.3:
suggestions.append({
"target_title": title,
"target_id": hit.node_id,
"suggested_markdown": f"[[rel:{edge_kind} {title}]]",
"reason": f"Semantisch ähnlich ({hit.total_score:.2f})",
"type": "semantic"
})
else:
logger.info(f" -> SKIPPED (Score too low)")
logger.info(f"RETURNING {len(suggestions)} SUGGESTIONS")
return {"suggestions": suggestions}
except Exception as e:
logger.error(f"Analyze failed: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=f"Analysis failed: {str(e)}")
@router.post("/save", response_model=SaveResponse)
async def save_note(req: SaveRequest):
"""WP-11 Persistence"""
try:
vault_root = os.getenv("MINDNET_VAULT_ROOT", "./vault")
abs_vault_root = os.path.abspath(vault_root)
if not os.path.exists(abs_vault_root):
os.makedirs(abs_vault_root, exist_ok=True)
final_filename = req.filename
if not final_filename:
final_filename = f"draft_{int(time.time())}.md"
ingest_service = IngestionService()
logger.info(f"Saving {final_filename}")
result = await ingest_service.save_and_index(
markdown_content=req.markdown_content,
filename=final_filename
)
if result.get("status") == "error":
raise HTTPException(status_code=500, detail=result.get("error"))
return SaveResponse(
status="success",
file_path=result.get("file_path", "unknown"),
note_id=result.get("note_id", "unknown"),
stats=result.get("stats", {})
)
except HTTPException as he:
raise he
except Exception as e:
logger.error(f"Save failed: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=f"Save failed: {str(e)}")