bug fixes

This commit is contained in:
Lars 2025-12-14 11:49:13 +01:00
parent 4e8512c812
commit c6ccad1d18

View File

@ -9,16 +9,22 @@ from ui_utils import parse_markdown_draft, build_markdown_doc, load_history_from
from ui_api import save_draft_to_vault, analyze_draft_text, send_chat_message, submit_feedback from ui_api import save_draft_to_vault, analyze_draft_text, send_chat_message, submit_feedback
from ui_config import HISTORY_FILE, COLLECTION_PREFIX, GRAPH_COLORS from ui_config import HISTORY_FILE, COLLECTION_PREFIX, GRAPH_COLORS
# --- Helper zum Modus-Wechsel --- # --- CALLBACKS ---
def switch_to_editor(note_payload): # Diese müssen oben definiert sein, damit sie VOR dem Re-Run bekannt sind.
"""Lädt eine Note in den Editor und wechselt den Tab."""
# Wir simulieren eine Message, wie sie der Chatbot zurückgeben würde def switch_to_editor_callback(note_payload):
"""
Callback-Funktion: Wird ausgeführt, wenn der 'Bearbeiten'-Button geklickt wird.
Da dies ein Callback ist, können wir session_state Werte ändern, bevor die UI neu gezeichnet wird.
"""
# 1. Inhalt vorbereiten
content = note_payload.get('fulltext', '') content = note_payload.get('fulltext', '')
if not content: if not content:
# Fallback: Wir rekonstruieren minimales Markdown # Fallback: Markdown aus Metadaten rekonstruieren, falls kein Fulltext da ist
content = build_markdown_doc(note_payload, "Inhalt konnte nicht geladen werden (nur Metadaten verfügbar).") content = build_markdown_doc(note_payload, "Inhalt konnte nicht geladen werden (nur Metadaten verfügbar).")
# State setzen für den Editor # 2. Nachricht simulieren (als ob der Chatbot sie generiert hätte)
# Dies füllt den Editor mit dem Inhalt der Notiz
st.session_state.messages.append({ st.session_state.messages.append({
"role": "assistant", "role": "assistant",
"intent": "INTERVIEW", "intent": "INTERVIEW",
@ -26,16 +32,19 @@ def switch_to_editor(note_payload):
"query_id": f"edit_{note_payload['note_id']}" "query_id": f"edit_{note_payload['note_id']}"
}) })
# Modus umschalten (muss via session_state key im Radio-Widget passieren) # 3. Modus umschalten
# Das ist der entscheidende Fix: Wir ändern den Wert des Radio-Buttons im State direkt.
st.session_state["sidebar_mode_selection"] = "📝 Manueller Editor" st.session_state["sidebar_mode_selection"] = "📝 Manueller Editor"
st.rerun()
# --- UI RENDERER ---
def render_sidebar(): def render_sidebar():
with st.sidebar: with st.sidebar:
st.title("🧠 mindnet") st.title("🧠 mindnet")
st.caption("v2.6 | WP-19 Graph View") st.caption("v2.6 | WP-19 Graph View")
# State-gebundenes Radio Widget für Modus-Wechsel # State-gebundenes Radio Widget
# Wir nutzen 'sidebar_mode_selection' als Key, damit wir ihn programmgesteuert (Callback) ändern können.
if "sidebar_mode_selection" not in st.session_state: if "sidebar_mode_selection" not in st.session_state:
st.session_state["sidebar_mode_selection"] = "💬 Chat" st.session_state["sidebar_mode_selection"] = "💬 Chat"
@ -60,7 +69,7 @@ def render_sidebar():
def render_draft_editor(msg): def render_draft_editor(msg):
""" """
Rendert den Editor für Drafts (genutzt im Chat bei INTERVIEW Intent oder im manuellen Modus). Der Editor-Kern. Wird sowohl im Chat (Interview-Modus) als auch im manuellen Modus verwendet.
""" """
if "query_id" not in msg or not msg["query_id"]: if "query_id" not in msg or not msg["query_id"]:
msg["query_id"] = str(uuid.uuid4()) msg["query_id"] = str(uuid.uuid4())
@ -296,18 +305,18 @@ def render_manual_editor():
} }
render_draft_editor(mock_msg) render_draft_editor(mock_msg)
# --- GRAPH EXPLORER (WP-19) --- # --- GRAPH EXPLORER ---
def render_graph_explorer(graph_service): def render_graph_explorer(graph_service):
st.header("🕸️ Graph Explorer") st.header("🕸️ Graph Explorer")
# State Init für den Graph-Explorer # State Init
if "graph_center_id" not in st.session_state: st.session_state.graph_center_id = None if "graph_center_id" not in st.session_state: st.session_state.graph_center_id = None
# Defaults speichern für Persistenz während der Session (mit setdefault) # Defaults speichern für Persistenz während der Session
st.session_state.setdefault("graph_depth", 2) st.session_state.setdefault("graph_depth", 2)
st.session_state.setdefault("graph_show_labels", True) st.session_state.setdefault("graph_show_labels", True)
st.session_state.setdefault("graph_spacing", 200) # Standard etwas höher für mehr Luft st.session_state.setdefault("graph_spacing", 200)
st.session_state.setdefault("graph_gravity", -3000) st.session_state.setdefault("graph_gravity", -3000)
col_ctrl, col_graph = st.columns([1, 4]) col_ctrl, col_graph = st.columns([1, 4])
@ -358,20 +367,21 @@ def render_graph_explorer(graph_service):
center_id = st.session_state.graph_center_id center_id = st.session_state.graph_center_id
if center_id: if center_id:
# 1. Action Bar für die aktive Node # Action Bar
c_action1, c_action2 = st.columns([3, 1]) c_action1, c_action2 = st.columns([3, 1])
with c_action1: with c_action1:
st.caption(f"Aktives Zentrum: **{center_id}**") st.caption(f"Aktives Zentrum: **{center_id}**")
with c_action2: with c_action2:
# Button um die aktuelle Zentrale Note zu editieren # FIX: Button mit Callback (on_click)
if st.button("📝 Bearbeiten", use_container_width=True):
note_data = graph_service._fetch_note_cached(center_id) note_data = graph_service._fetch_note_cached(center_id)
if note_data: if note_data:
switch_to_editor(note_data) st.button("📝 Bearbeiten",
use_container_width=True,
on_click=switch_to_editor_callback,
args=(note_data,))
else: else:
st.error("Fehler beim Laden der Daten.") st.error("Datenfehler")
# 2. Graph Rendern
with st.spinner(f"Lade Graph..."): with st.spinner(f"Lade Graph..."):
nodes, edges = graph_service.get_ego_graph( nodes, edges = graph_service.get_ego_graph(
center_id, center_id,
@ -382,6 +392,9 @@ def render_graph_explorer(graph_service):
if not nodes: if not nodes:
st.warning("Keine Daten gefunden. (Notiz existiert evtl. nicht mehr)") st.warning("Keine Daten gefunden. (Notiz existiert evtl. nicht mehr)")
else: else:
# FIX: Dynamischer Key erzwingt Neu-Rendern bei Physics-Änderung
graph_key = f"graph_{center_id}_{st.session_state.graph_gravity}_{st.session_state.graph_spacing}"
config = Config( config = Config(
width=1000, width=1000,
height=800, height=800,
@ -395,26 +408,23 @@ def render_graph_explorer(graph_service):
solver="forceAtlas2Based", solver="forceAtlas2Based",
forceAtlas2Based={ forceAtlas2Based={
"theta": 0.5, "theta": 0.5,
"gravitationalConstant": st.session_state.graph_gravity, # Dynamisch "gravitationalConstant": st.session_state.graph_gravity,
"centralGravity": 0.005, "centralGravity": 0.005,
"springConstant": 0.08, "springConstant": 0.08,
"springLength": st.session_state.graph_spacing, # Dynamisch "springLength": st.session_state.graph_spacing,
"damping": 0.4, "damping": 0.4,
"avoidOverlap": 1 "avoidOverlap": 1
}, },
stabilization={"enabled": True, "iterations": 800} stabilization={"enabled": True, "iterations": 800}
) )
# Interaktion return_value = agraph(nodes=nodes, edges=edges, config=config, key=graph_key)
return_value = agraph(nodes=nodes, edges=edges, config=config)
if return_value: if return_value:
# Wenn auf eine andere Node geklickt wurde:
if return_value != center_id: if return_value != center_id:
st.session_state.graph_center_id = return_value st.session_state.graph_center_id = return_value
st.rerun() st.rerun()
else: else:
# Wenn auf die ZENTRALE Node geklickt wurde
st.toast(f"Zentrum: {return_value}") st.toast(f"Zentrum: {return_value}")
else: else: