diff --git a/app/frontend/ui.py b/app/frontend/ui.py index 733bcb4..c0079f1 100644 --- a/app/frontend/ui.py +++ b/app/frontend/ui.py @@ -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 # --- PAGE SETUP --- -st.set_page_config(page_title="mindnet v2.3.10", page_icon="🧠", layout="wide") +st.set_page_config(page_title="mindnet v2.4", page_icon="🧠", layout="wide") # --- CSS STYLING --- st.markdown(""" @@ -225,7 +225,7 @@ def submit_feedback(query_id, node_id, score, comment=None): def render_sidebar(): with st.sidebar: st.title("🧠 mindnet") - st.caption("v2.3.10 | Mode Switch Fix") + st.caption("v2.4 | Async Intelligence") mode = st.radio("Modus", ["💬 Chat", "📝 Manueller Editor"], index=0) st.divider() st.subheader("⚙️ Settings") @@ -266,15 +266,28 @@ def render_draft_editor(msg): st.session_state[data_sugg_key] = [] st.session_state[data_body_key] = body.strip() + # WIDGET KEYS INITIALISIEREN (Resurrection Fix) + # Wir setzen die Werte direkt in den Widget-Key, damit Streamlit sie beim ersten Render findet. + st.session_state[f"{key_base}_wdg_title"] = meta["title"] + st.session_state[f"{key_base}_wdg_type"] = meta["type"] + st.session_state[f"{key_base}_wdg_tags"] = meta["tags_str"] + st.session_state[f"{key_base}_init"] = True - # --- 2. RESURRECTION FIX (WICHTIG!) --- - # Wenn wir vom Manuellen Editor zurückkommen, wurde der widget_key von Streamlit gelöscht. - # Wir müssen ihn aus dem persistenten data_body_key wiederherstellen. + # --- 2. RESURRECTION FIX (Body) --- + # Wenn wir vom Manuellen Editor zurückkommen, ist das Widget weg, aber die Daten sind noch da. if widget_body_key not in st.session_state and data_body_key in st.session_state: st.session_state[widget_body_key] = st.session_state[data_body_key] # --- CALLBACKS --- + def _sync_meta(): + # Schreibt Widget-Werte zurück in den Meta-Store + meta = st.session_state[data_meta_key] + meta["title"] = st.session_state.get(f"{key_base}_wdg_title", "") + meta["type"] = st.session_state.get(f"{key_base}_wdg_type", "default") + meta["tags_str"] = st.session_state.get(f"{key_base}_wdg_tags", "") + st.session_state[data_meta_key] = meta + def _sync_body(): # Sync Widget -> Data (Source of Truth) st.session_state[data_body_key] = st.session_state[widget_body_key] @@ -300,29 +313,26 @@ def render_draft_editor(msg): meta_ref = st.session_state[data_meta_key] c1, c2 = st.columns([2, 1]) with c1: - # Auch hier Keys für Widgets nutzen, um Resets zu vermeiden - title_key = f"{key_base}_wdg_title" - if title_key not in st.session_state: st.session_state[title_key] = meta_ref["title"] - meta_ref["title"] = st.text_input("Titel", key=title_key) + # FIX: Keine 'value=' Angabe, da der Key schon existiert + st.text_input("Titel", key=f"{key_base}_wdg_title", on_change=_sync_meta) with c2: - known_types = ["concept", "project", "decision", "experience", "journal", "value", "goal", "principle"] - curr = meta_ref["type"] - if curr not in known_types: known_types.append(curr) - type_key = f"{key_base}_wdg_type" - if type_key not in st.session_state: st.session_state[type_key] = meta_ref["type"] - meta_ref["type"] = st.selectbox("Typ", known_types, index=known_types.index(curr) if curr in known_types else 0, key=type_key) + known_types = ["concept", "project", "decision", "experience", "journal", "value", "goal", "principle", "risk", "belief"] + # Sicherstellen, dass der aktuelle Typ in der Liste ist + curr_type = st.session_state.get(f"{key_base}_wdg_type", meta_ref["type"]) + if curr_type not in known_types: known_types.append(curr_type) + + # FIX: Keine 'index=' Angabe, da der Key schon existiert + st.selectbox("Typ", known_types, key=f"{key_base}_wdg_type", on_change=_sync_meta) - tags_key = f"{key_base}_wdg_tags" - if tags_key not in st.session_state: st.session_state[tags_key] = meta_ref.get("tags_str", "") - meta_ref["tags_str"] = st.text_input("Tags", key=tags_key) + # Tags + st.text_input("Tags", key=f"{key_base}_wdg_tags", on_change=_sync_meta) # Tabs tab_edit, tab_intel, tab_view = st.tabs(["✏️ Inhalt", "🧠 Intelligence", "👁️ Vorschau"]) # --- TAB 1: EDITOR --- with tab_edit: - # Hier kein 'value' Argument mehr, da wir den Key oben (Resurrection) initialisiert haben. st.text_area( "Body", key=widget_body_key, @@ -340,9 +350,10 @@ def render_draft_editor(msg): # Lese vom Widget (aktuell) oder Data (Fallback) text_to_analyze = st.session_state.get(widget_body_key, st.session_state.get(data_body_key, "")) - + current_doc_type = st.session_state.get(f"{key_base}_wdg_type", "concept") + with st.spinner("Analysiere..."): - analysis = analyze_draft_text(text_to_analyze, meta_ref["type"]) + analysis = analyze_draft_text(text_to_analyze, current_doc_type) if "error" in analysis: st.error(f"Fehler: {analysis['error']}") @@ -380,11 +391,13 @@ def render_draft_editor(msg): st.button("➕ Einfügen", key=f"add_{idx}_{key_base}", on_click=_insert_text, args=(link_text,)) # --- TAB 3: SAVE --- - final_tags = [t.strip() for t in meta_ref["tags_str"].split(",") if t.strip()] + final_tags_str = st.session_state.get(f"{key_base}_wdg_tags", "") + final_tags = [t.strip() for t in final_tags_str.split(",") if t.strip()] + final_meta = { "id": "generated_on_save", - "type": meta_ref["type"], - "title": meta_ref["title"], + "type": st.session_state.get(f"{key_base}_wdg_type", "default"), + "title": st.session_state.get(f"{key_base}_wdg_title", "Untitled"), "status": "draft", "tags": final_tags } @@ -403,7 +416,7 @@ def render_draft_editor(msg): with b1: if st.button("💾 Speichern & Indizieren", type="primary", key=f"{key_base}_save"): with st.spinner("Speichere im Vault..."): - safe_title = re.sub(r'[^a-zA-Z0-9]', '-', meta_ref["title"]).lower()[:30] or "draft" + safe_title = re.sub(r'[^a-zA-Z0-9]', '-', final_meta["title"]).lower()[:30] or "draft" fname = f"{datetime.now().strftime('%Y%m%d')}-{safe_title}.md" result = save_draft_to_vault(final_doc, filename=fname)