WP10 Überarbeitung
This commit is contained in:
parent
06f77fe8b7
commit
f4299db347
|
|
@ -23,7 +23,7 @@ timeout_setting = os.getenv("MINDNET_API_TIMEOUT") or os.getenv("MINDNET_LLM_TIM
|
||||||
API_TIMEOUT = float(timeout_setting) if timeout_setting else 300.0
|
API_TIMEOUT = float(timeout_setting) if timeout_setting else 300.0
|
||||||
|
|
||||||
# --- PAGE SETUP ---
|
# --- PAGE SETUP ---
|
||||||
st.set_page_config(page_title="mindnet v2.3.2", page_icon="🧠", layout="wide")
|
st.set_page_config(page_title="mindnet v2.3.4", page_icon="🧠", layout="wide")
|
||||||
|
|
||||||
# --- CSS STYLING ---
|
# --- CSS STYLING ---
|
||||||
st.markdown("""
|
st.markdown("""
|
||||||
|
|
@ -194,7 +194,7 @@ def analyze_draft_text(text: str, n_type: str):
|
||||||
response = requests.post(
|
response = requests.post(
|
||||||
INGEST_ANALYZE_ENDPOINT,
|
INGEST_ANALYZE_ENDPOINT,
|
||||||
json={"text": text, "type": n_type},
|
json={"text": text, "type": n_type},
|
||||||
timeout=15 # Erhöhtes Timeout für Suche
|
timeout=15
|
||||||
)
|
)
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
return response.json()
|
return response.json()
|
||||||
|
|
@ -225,7 +225,7 @@ def submit_feedback(query_id, node_id, score, comment=None):
|
||||||
def render_sidebar():
|
def render_sidebar():
|
||||||
with st.sidebar:
|
with st.sidebar:
|
||||||
st.title("🧠 mindnet")
|
st.title("🧠 mindnet")
|
||||||
st.caption("v2.3.3 | WP-10b (Intelligence)")
|
st.caption("v2.3.4 | WP-10b (Intelligence)")
|
||||||
mode = st.radio("Modus", ["💬 Chat", "📝 Manueller Editor"], index=0)
|
mode = st.radio("Modus", ["💬 Chat", "📝 Manueller Editor"], index=0)
|
||||||
st.divider()
|
st.divider()
|
||||||
st.subheader("⚙️ Settings")
|
st.subheader("⚙️ Settings")
|
||||||
|
|
@ -243,7 +243,7 @@ def render_draft_editor(msg):
|
||||||
qid = msg.get('query_id', str(uuid.uuid4()))
|
qid = msg.get('query_id', str(uuid.uuid4()))
|
||||||
key_base = f"draft_{qid}"
|
key_base = f"draft_{qid}"
|
||||||
|
|
||||||
# 1. Init
|
# 1. Init (Nur beim allerersten Laden)
|
||||||
if f"{key_base}_init" not in st.session_state:
|
if f"{key_base}_init" not in st.session_state:
|
||||||
meta, body = parse_markdown_draft(msg["content"])
|
meta, body = parse_markdown_draft(msg["content"])
|
||||||
|
|
||||||
|
|
@ -263,19 +263,89 @@ def render_draft_editor(msg):
|
||||||
# Metadata
|
# Metadata
|
||||||
c1, c2 = st.columns([2, 1])
|
c1, c2 = st.columns([2, 1])
|
||||||
with c1:
|
with c1:
|
||||||
new_title = st.text_input("Titel", value=st.session_state.get(f"{key_base}_title", ""), key=f"{key_base}_inp_title")
|
# Titel immer aus State lesen/schreiben
|
||||||
|
new_title = st.text_input("Titel", key=f"{key_base}_inp_title", value=st.session_state.get(f"{key_base}_title", ""))
|
||||||
with c2:
|
with c2:
|
||||||
known_types = ["concept", "project", "decision", "experience", "journal", "person", "value", "goal", "principle", "default"]
|
known_types = ["concept", "project", "decision", "experience", "journal", "person", "value", "goal", "principle", "default"]
|
||||||
curr_type = st.session_state.get(f"{key_base}_type", "default")
|
curr_type = st.session_state.get(f"{key_base}_type", "default")
|
||||||
if curr_type not in known_types: known_types.append(curr_type)
|
if curr_type not in known_types: known_types.append(curr_type)
|
||||||
new_type = st.selectbox("Typ", known_types, index=known_types.index(curr_type), key=f"{key_base}_sel_type")
|
new_type = st.selectbox("Typ", known_types, index=known_types.index(curr_type), key=f"{key_base}_sel_type")
|
||||||
|
|
||||||
new_tags = st.text_input("Tags (kommagetrennt)", value=st.session_state.get(f"{key_base}_tags", ""), key=f"{key_base}_inp_tags")
|
new_tags = st.text_input("Tags (kommagetrennt)", key=f"{key_base}_inp_tags", value=st.session_state.get(f"{key_base}_tags", ""))
|
||||||
|
|
||||||
# Tabs (Jetzt mit "Intelligence")
|
# Tabs
|
||||||
tab_edit, tab_intel, tab_view = st.tabs(["✏️ Inhalt", "🧠 Intelligence", "👁️ Vorschau"])
|
tab_edit, tab_intel, tab_view = st.tabs(["✏️ Inhalt", "🧠 Intelligence", "👁️ Vorschau"])
|
||||||
|
|
||||||
# Live Reassembly für alle Tabs
|
# --- TAB 1: EDITOR ---
|
||||||
|
with tab_edit:
|
||||||
|
# WICHTIG: Das Text-Area ist an session_state gebunden via 'key'.
|
||||||
|
current_body = st.text_area(
|
||||||
|
"Body",
|
||||||
|
key=f"{key_base}_txt_body", # Master-Key
|
||||||
|
value=st.session_state.get(f"{key_base}_body", ""),
|
||||||
|
height=500,
|
||||||
|
label_visibility="collapsed"
|
||||||
|
)
|
||||||
|
# Sync zurück zum generischen Key für andere Tabs
|
||||||
|
st.session_state[f"{key_base}_body"] = current_body
|
||||||
|
|
||||||
|
# --- TAB 2: INTELLIGENCE ---
|
||||||
|
with tab_intel:
|
||||||
|
st.info("Klicke auf 'Analysieren', um Verknüpfungen für den AKTUELLEN Text zu finden.")
|
||||||
|
|
||||||
|
if st.button("🔍 Analyse starten", key=f"{key_base}_analyze"):
|
||||||
|
with st.spinner("Analysiere..."):
|
||||||
|
# Wir nehmen explizit den Text aus dem Widget-State
|
||||||
|
text_to_analyze = st.session_state[f"{key_base}_txt_body"]
|
||||||
|
analysis = analyze_draft_text(text_to_analyze, new_type)
|
||||||
|
|
||||||
|
if "error" in analysis:
|
||||||
|
st.error(f"Fehler: {analysis['error']}")
|
||||||
|
else:
|
||||||
|
suggestions = analysis.get("suggestions", [])
|
||||||
|
st.session_state[f"{key_base}_suggestions"] = suggestions
|
||||||
|
if not suggestions:
|
||||||
|
st.warning("Keine Vorschläge gefunden.")
|
||||||
|
|
||||||
|
suggestions = st.session_state.get(f"{key_base}_suggestions", [])
|
||||||
|
if suggestions:
|
||||||
|
st.write(f"**{len(suggestions)} Vorschläge:**")
|
||||||
|
for idx, sugg in enumerate(suggestions):
|
||||||
|
link_text = sugg.get('suggested_markdown', '')
|
||||||
|
|
||||||
|
# Check: Ist der Link schon im Text?
|
||||||
|
is_inserted = link_text in st.session_state[f"{key_base}_txt_body"]
|
||||||
|
|
||||||
|
# Card Styling
|
||||||
|
card_style = "border-left: 3px solid #28a745;" if is_inserted else "border-left: 3px solid #1a73e8;"
|
||||||
|
bg_color = "#e6fffa" if is_inserted else "#ffffff"
|
||||||
|
|
||||||
|
st.markdown(f"""
|
||||||
|
<div style="{card_style} background-color: {bg_color}; padding: 10px; margin-bottom: 8px; border-radius: 4px; box-shadow: 0 1px 3px rgba(0,0,0,0.1);">
|
||||||
|
<b>{sugg.get('target_title', 'Unbekannt')}</b> <small>({sugg.get('type', 'semantic')})</small><br>
|
||||||
|
<i>{sugg.get('reason', 'N/A')}</i><br>
|
||||||
|
<code>{link_text}</code>
|
||||||
|
</div>
|
||||||
|
""", unsafe_allow_html=True)
|
||||||
|
|
||||||
|
# Button Logik (Toggle)
|
||||||
|
if is_inserted:
|
||||||
|
if st.button(f"❌ Entfernen", key=f"del_{idx}_{key_base}"):
|
||||||
|
new_text = st.session_state[f"{key_base}_txt_body"].replace(link_text, "").strip()
|
||||||
|
st.session_state[f"{key_base}_txt_body"] = new_text
|
||||||
|
st.session_state[f"{key_base}_body"] = new_text
|
||||||
|
st.rerun()
|
||||||
|
else:
|
||||||
|
if st.button(f"➕ Einfügen", key=f"add_{idx}_{key_base}"):
|
||||||
|
old_text = st.session_state[f"{key_base}_txt_body"]
|
||||||
|
new_text = f"{old_text}\n\n{link_text}"
|
||||||
|
st.session_state[f"{key_base}_txt_body"] = new_text
|
||||||
|
st.session_state[f"{key_base}_body"] = new_text
|
||||||
|
st.rerun()
|
||||||
|
|
||||||
|
# --- TAB 3: PREVIEW & SAVE ---
|
||||||
|
|
||||||
|
# Reassemble Metadata & Body (Always use latest state)
|
||||||
final_tags_list = [t.strip() for t in new_tags.split(",") if t.strip()]
|
final_tags_list = [t.strip() for t in new_tags.split(",") if t.strip()]
|
||||||
final_meta = {
|
final_meta = {
|
||||||
"id": "generated_on_save",
|
"id": "generated_on_save",
|
||||||
|
|
@ -285,57 +355,10 @@ def render_draft_editor(msg):
|
||||||
"tags": final_tags_list
|
"tags": final_tags_list
|
||||||
}
|
}
|
||||||
|
|
||||||
# --- TAB 1: EDITOR ---
|
# Wir nehmen den aktuellsten Body aus dem State
|
||||||
with tab_edit:
|
final_body_content = st.session_state.get(f"{key_base}_txt_body", "")
|
||||||
new_body = st.text_area(
|
final_doc = build_markdown_doc(final_meta, final_body_content)
|
||||||
"Body",
|
|
||||||
value=st.session_state.get(f"{key_base}_body", ""),
|
|
||||||
height=500,
|
|
||||||
key=f"{key_base}_txt_body",
|
|
||||||
label_visibility="collapsed"
|
|
||||||
)
|
|
||||||
|
|
||||||
# --- TAB 2: INTELLIGENCE (WP-11 Features) ---
|
|
||||||
with tab_intel:
|
|
||||||
st.info("Klicke auf 'Analysieren', um Verknüpfungen zu finden.")
|
|
||||||
|
|
||||||
if st.button("🔍 Analyse starten", key=f"{key_base}_analyze"):
|
|
||||||
with st.spinner("Analysiere Text und suche Verknüpfungen..."):
|
|
||||||
current_text = st.session_state[f"{key_base}_body"]
|
|
||||||
# API Call
|
|
||||||
analysis = analyze_draft_text(current_text, new_type)
|
|
||||||
|
|
||||||
if "error" in analysis:
|
|
||||||
st.error(f"Fehler: {analysis['error']}")
|
|
||||||
else:
|
|
||||||
suggestions = analysis.get("suggestions", [])
|
|
||||||
st.session_state[f"{key_base}_suggestions"] = suggestions
|
|
||||||
if not suggestions:
|
|
||||||
st.warning("Keine offensichtlichen Verknüpfungen gefunden.")
|
|
||||||
|
|
||||||
# Anzeige der Vorschläge
|
|
||||||
suggestions = st.session_state.get(f"{key_base}_suggestions", [])
|
|
||||||
if suggestions:
|
|
||||||
st.markdown(f"**{len(suggestions)} Vorschläge gefunden:**")
|
|
||||||
for idx, sugg in enumerate(suggestions):
|
|
||||||
with st.container():
|
|
||||||
st.markdown(f"""
|
|
||||||
<div class="suggestion-card">
|
|
||||||
<b>{sugg.get('target_title', 'Unbekannt')}</b> <small>({sugg.get('type', 'semantic')})</small><br>
|
|
||||||
<i>Grund: {sugg.get('reason', 'N/A')}</i><br>
|
|
||||||
<code>{sugg.get('suggested_markdown', '')}</code>
|
|
||||||
</div>
|
|
||||||
""", unsafe_allow_html=True)
|
|
||||||
|
|
||||||
if st.button("➕ Einfügen", key=f"{key_base}_add_{idx}"):
|
|
||||||
current_body = st.session_state[f"{key_base}_body"]
|
|
||||||
updated_body = f"{current_body}\n\n{sugg['suggested_markdown']}"
|
|
||||||
st.session_state[f"{key_base}_body"] = updated_body
|
|
||||||
st.toast(f"Link zu '{sugg.get('target_title', '?')}' eingefügt!")
|
|
||||||
st.rerun()
|
|
||||||
|
|
||||||
# --- TAB 3: PREVIEW ---
|
|
||||||
final_doc = build_markdown_doc(final_meta, st.session_state.get(f"{key_base}_body", ""))
|
|
||||||
with tab_view:
|
with tab_view:
|
||||||
st.markdown('<div class="preview-box">', unsafe_allow_html=True)
|
st.markdown('<div class="preview-box">', unsafe_allow_html=True)
|
||||||
st.markdown(final_doc)
|
st.markdown(final_doc)
|
||||||
|
|
@ -343,24 +366,19 @@ def render_draft_editor(msg):
|
||||||
|
|
||||||
st.markdown("---")
|
st.markdown("---")
|
||||||
|
|
||||||
# Actions (SAVE & EXPORT)
|
# Save Action
|
||||||
b1, b2 = st.columns([1, 1])
|
b1, b2 = st.columns([1, 1])
|
||||||
with b1:
|
with b1:
|
||||||
# Echter Save Button (Ruft API auf)
|
|
||||||
if st.button("💾 Speichern & Indizieren", type="primary", key=f"{key_base}_save"):
|
if st.button("💾 Speichern & Indizieren", type="primary", key=f"{key_base}_save"):
|
||||||
with st.spinner("Speichere im Vault..."):
|
with st.spinner("Speichere im Vault..."):
|
||||||
# Generiere Filename
|
|
||||||
safe_title = re.sub(r'[^a-zA-Z0-9]', '-', new_title).lower()[:30]
|
safe_title = re.sub(r'[^a-zA-Z0-9]', '-', new_title).lower()[:30]
|
||||||
fname = f"{datetime.now().strftime('%Y%m%d')}-{safe_title}.md"
|
fname = f"{datetime.now().strftime('%Y%m%d')}-{safe_title}.md"
|
||||||
|
|
||||||
# Wir holen den aktuellsten Stand aus dem State (inklusive eingefügter Links)
|
# Hier der entscheidende Call mit dem aktuellen Dokument
|
||||||
latest_body = st.session_state.get(f"{key_base}_body", "")
|
result = save_draft_to_vault(final_doc, filename=fname)
|
||||||
latest_doc = build_markdown_doc(final_meta, latest_body)
|
|
||||||
|
|
||||||
result = save_draft_to_vault(latest_doc, filename=fname)
|
|
||||||
|
|
||||||
if "error" in result:
|
if "error" in result:
|
||||||
st.error(f"Fehler beim Speichern: {result['error']}")
|
st.error(f"Fehler: {result['error']}")
|
||||||
else:
|
else:
|
||||||
st.success(f"Gespeichert: {result.get('file_path')}")
|
st.success(f"Gespeichert: {result.get('file_path')}")
|
||||||
st.balloons()
|
st.balloons()
|
||||||
|
|
@ -447,6 +465,7 @@ def render_manual_editor():
|
||||||
else:
|
else:
|
||||||
st.success(f"Gespeichert: {res.get('file_path')}")
|
st.success(f"Gespeichert: {res.get('file_path')}")
|
||||||
|
|
||||||
|
# --- MAIN ---
|
||||||
mode, top_k, explain = render_sidebar()
|
mode, top_k, explain = render_sidebar()
|
||||||
if mode == "💬 Chat":
|
if mode == "💬 Chat":
|
||||||
render_chat_interface(top_k, explain)
|
render_chat_interface(top_k, explain)
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,27 @@
|
||||||
"""
|
"""
|
||||||
app/routers/ingest.py - DEBUG VERSION
|
app/routers/ingest.py
|
||||||
|
API-Endpunkte für WP-11 (Discovery & Persistence).
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
import logging
|
import logging
|
||||||
from fastapi import APIRouter, HTTPException
|
from fastapi import APIRouter, HTTPException
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from typing import Optional, List, Dict, Any
|
from typing import Optional, Dict, Any
|
||||||
|
|
||||||
from app.core.ingestion import IngestionService
|
from app.core.ingestion import IngestionService
|
||||||
|
# Fallback: Falls DiscoveryService noch fehlt, nutzen wir Ingest Service Features oder Mock
|
||||||
|
# Wir gehen hier davon aus, dass wir alles im IngestionService oder Router machen können,
|
||||||
|
# um Importfehler zu vermeiden.
|
||||||
from app.core.retriever import Retriever
|
from app.core.retriever import Retriever
|
||||||
from app.models.dto import QueryRequest
|
from app.models.dto import QueryRequest
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
# --- DTOs ---
|
# --- DTOs ---
|
||||||
|
|
||||||
class AnalyzeRequest(BaseModel):
|
class AnalyzeRequest(BaseModel):
|
||||||
text: str
|
text: str
|
||||||
type: str = "concept"
|
type: str = "concept"
|
||||||
|
|
@ -37,43 +43,36 @@ class SaveResponse(BaseModel):
|
||||||
async def analyze_draft(req: AnalyzeRequest):
|
async def analyze_draft(req: AnalyzeRequest):
|
||||||
"""
|
"""
|
||||||
WP-11 Intelligence: Liefert Link-Vorschläge.
|
WP-11 Intelligence: Liefert Link-Vorschläge.
|
||||||
DEBUG MODE: Threshold gesenkt, Logging erhöht.
|
Implementiert direkt hier, um Abhängigkeiten zu reduzieren.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
retriever = Retriever()
|
retriever = Retriever()
|
||||||
suggestions = []
|
suggestions = []
|
||||||
|
|
||||||
query_text = req.text[:400]
|
query_text = req.text[:400]
|
||||||
logger.info(f"ANALYZING TEXT: '{query_text}' (Type: {req.type})")
|
|
||||||
|
|
||||||
if not query_text.strip():
|
if not query_text.strip():
|
||||||
return {"suggestions": []}
|
return {"suggestions": []}
|
||||||
|
|
||||||
# Wir suchen
|
# 1. Semantic Search
|
||||||
|
# Safe async call check
|
||||||
|
if hasattr(retriever.search, '__await__'):
|
||||||
|
hits_result = await retriever.search(QueryRequest(query=query_text, top_k=5, mode="hybrid"))
|
||||||
|
else:
|
||||||
hits_result = await retriever.search(QueryRequest(query=query_text, top_k=5, mode="hybrid"))
|
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()
|
seen_titles = set()
|
||||||
for hit in hits_result.results:
|
for hit in hits_result.results:
|
||||||
# Titel holen
|
# Titel ermitteln
|
||||||
title = hit.payload.get("title") or hit.payload.get("note_id") or hit.node_id
|
title = hit.payload.get("note_id") or hit.node_id
|
||||||
|
if not title or title in seen_titles: continue
|
||||||
# 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)
|
seen_titles.add(title)
|
||||||
|
|
||||||
# Edge Logic
|
|
||||||
edge_kind = "related_to"
|
edge_kind = "related_to"
|
||||||
if req.type == "project": edge_kind = "depends_on"
|
if req.type == "project": edge_kind = "depends_on"
|
||||||
if req.type == "decision": edge_kind = "references"
|
if req.type == "decision": edge_kind = "references"
|
||||||
|
|
||||||
# --- ÄNDERUNG: THRESHOLD GESENKT ---
|
# Score Threshold
|
||||||
# War vorher 0.65. Jetzt 0.3 für Tests.
|
if hit.total_score > 0.4: # Etwas toleranter
|
||||||
if hit.total_score > 0.3:
|
|
||||||
suggestions.append({
|
suggestions.append({
|
||||||
"target_title": title,
|
"target_title": title,
|
||||||
"target_id": hit.node_id,
|
"target_id": hit.node_id,
|
||||||
|
|
@ -81,19 +80,19 @@ async def analyze_draft(req: AnalyzeRequest):
|
||||||
"reason": f"Semantisch ähnlich ({hit.total_score:.2f})",
|
"reason": f"Semantisch ähnlich ({hit.total_score:.2f})",
|
||||||
"type": "semantic"
|
"type": "semantic"
|
||||||
})
|
})
|
||||||
else:
|
|
||||||
logger.info(f" -> SKIPPED (Score too low)")
|
|
||||||
|
|
||||||
logger.info(f"RETURNING {len(suggestions)} SUGGESTIONS")
|
|
||||||
return {"suggestions": suggestions}
|
return {"suggestions": suggestions}
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Analyze failed: {e}", exc_info=True)
|
logger.error(f"Analyze failed: {e}", exc_info=True)
|
||||||
raise HTTPException(status_code=500, detail=f"Analysis failed: {str(e)}")
|
# Kein 500er werfen, lieber leere Liste, damit UI nicht crasht
|
||||||
|
return {"suggestions": [], "error": str(e)}
|
||||||
|
|
||||||
@router.post("/save", response_model=SaveResponse)
|
@router.post("/save", response_model=SaveResponse)
|
||||||
async def save_note(req: SaveRequest):
|
async def save_note(req: SaveRequest):
|
||||||
"""WP-11 Persistence"""
|
"""
|
||||||
|
WP-11 Persistence: Speichert Markdown physisch und indiziert es sofort.
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
vault_root = os.getenv("MINDNET_VAULT_ROOT", "./vault")
|
vault_root = os.getenv("MINDNET_VAULT_ROOT", "./vault")
|
||||||
abs_vault_root = os.path.abspath(vault_root)
|
abs_vault_root = os.path.abspath(vault_root)
|
||||||
|
|
@ -106,19 +105,28 @@ async def save_note(req: SaveRequest):
|
||||||
final_filename = f"draft_{int(time.time())}.md"
|
final_filename = f"draft_{int(time.time())}.md"
|
||||||
|
|
||||||
ingest_service = IngestionService()
|
ingest_service = IngestionService()
|
||||||
logger.info(f"Saving {final_filename}")
|
|
||||||
|
|
||||||
result = await ingest_service.save_and_index(
|
logger.info(f"Saving {final_filename} to {req.folder}")
|
||||||
markdown_content=req.markdown_content,
|
|
||||||
filename=final_filename
|
# --- AWAIT WICHTIG! ---
|
||||||
)
|
# Wir rufen save_and_index auf (so hieß es in meiner IngestionService Implementierung)
|
||||||
|
# Wenn deine Methode create_from_text heißt, ändere es hier entsprechend.
|
||||||
|
# Ich nutze hier save_and_index als Standard aus WP-11.
|
||||||
|
|
||||||
|
if hasattr(ingest_service, 'save_and_index'):
|
||||||
|
result = await ingest_service.save_and_index(req.markdown_content, final_filename)
|
||||||
|
elif hasattr(ingest_service, 'create_from_text'):
|
||||||
|
# Fallback falls du die alte Version hast
|
||||||
|
result = await ingest_service.create_from_text(req.markdown_content, final_filename, abs_vault_root, req.folder)
|
||||||
|
else:
|
||||||
|
raise RuntimeError("IngestionService hat weder save_and_index noch create_from_text")
|
||||||
|
|
||||||
if result.get("status") == "error":
|
if result.get("status") == "error":
|
||||||
raise HTTPException(status_code=500, detail=result.get("error"))
|
raise HTTPException(status_code=500, detail=result.get("error"))
|
||||||
|
|
||||||
return SaveResponse(
|
return SaveResponse(
|
||||||
status="success",
|
status="success",
|
||||||
file_path=result.get("file_path", "unknown"),
|
file_path=result.get("file_path") or result.get("path", "unknown"),
|
||||||
note_id=result.get("note_id", "unknown"),
|
note_id=result.get("note_id", "unknown"),
|
||||||
stats=result.get("stats", {})
|
stats=result.get("stats", {})
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user